video room文档:https://janus.conf.meetecho.com/docs/videoroom.html
room-<unique room ID>: {
# 房间描述
description = This is my awesome room
# 是否是私有房间,当提出“list”请求时,私人房间不会出现
is_private = true|false (private rooms don't appear when you do a 'list' request, default=false)
# 密码,操作房间时需要携带
secret = <optional password needed for manipulating (e.g. destroying) the room>
# 密码,加⼊房间时使⽤
pin = <optional password needed for joining the room>
# 订阅者是否需要提供⼀个有效的与发布者关联的有效private_id
require_pvtid = true|false (whether subscriptions are required to provide a valid private_id
to associate with a publisher, default=false)
# 房间内最⼤的发布者数量
publishers = <max number of concurrent senders> (e.g., 6 for a video
conference or 1 for a webinar, default=3)
# 发送者最⼤的视频⽐特率
bitrate = <max video bitrate for senders> (e.g., 128000)
bitrate_cap = <true|false, whether the above cap should act as a limit to dynamic bitrate changes by publishers, default=false>,
# FIR指令
fir_freq = <send a FIR to publishers every fir_freq seconds> (0=disable)
# ⾳频编码器,从左到右的优先级
audiocodec = opus|g722|pcmu|pcma|isac32|isac16 (audio codec to force on publishers, default=opus
can be a comma separated list in order of preference, e.g., opus,pcmu)
# 视频编码器,从左到右的优先级
videocodec = vp8|vp9|h264|av1|h265 (video codec to force on publishers, default=vp8
can be a comma separated list in order of preference, e.g., vp9,vp8,h264)
vp9_profile = VP9-specific profile to prefer (e.g., "2" for "profile-id=2")
h264_profile = H.264-specific profile to prefer (e.g., "42e01f" for "profile-level-id=42e01f")
# 是否使⽤内置FEC
opus_fec = true|false (whether inband FEC must be negotiated; only works for Opus, default=false)
# 是否⽀持编码SVC模式,⽬前只⽀持VP9
video_svc = true|false (whether SVC support must be enabled; only works for VP9, default=false)
audiolevel_ext = true|false (whether the ssrc-audio-level RTP extension must be
negotiated/used or not for new publishers, 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)
videoorient_ext = true|false (whether the video-orientation RTP extension must be
negotiated/used or not for new publishers, default=true)
playoutdelay_ext = true|false (whether the playout-delay RTP extension must be
negotiated/used or not for new publishers, default=true)
transport_wide_cc_ext = true|false (whether the transport wide CC RTP extension must be
negotiated/used or not for new publishers, default=true)
# 是否录制
record = true|false (whether this room should be recorded, default=false)
# 录制⽬录
rec_dir = <folder where recordings should be stored, when enabled>
lock_record = true|false (whether recording can only be started/stopped if the secret
is provided, or using the global enable_recording request, default=false)
# 当新⼈加⼊时是否通知所有的参会者
notify_joining = true|false (optional, whether to notify all participants when a new
participant joins the room. The Videoroom plugin by design only notifies
new feeds (publishers), and enabling this may result extra notification
traffic. This flag is particularly useful when enabled with require_pvtid
for admin to manage listening only participants. default=false)
# 是否使⽤端对端加密
require_e2ee = true|false (whether all participants are required to publish and subscribe
using end-to-end media encryption, e.g., via Insertable Streams; default=false)
}
{
"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" : "" ,
"secret" : "" ,
"pin" : "" ,
"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],
...
}
{
"videoroom" : "created",
"room" : <unique numeric ID>,
"permanent" : <true if saved to config file, false if not>
}
{
"videoroom" : "event",
"error_code" : <numeric ID, check Macros below>,
"error" : ""
}
{
"request" : "edit",
"room" : <unique numeric ID of the room to edit>,
"secret" : "" ,
"new_description" : "" ,
"new_secret" : "" ,
"new_pin" : "" ,
"new_is_private" : <true|false, whether the room should appear in a list request>,
"new_require_pvtid" : <true|false, whether the room should require private_id from subscribers>,
"new_bitrate" : <new bitrate cap to force on all publishers (except those with custom overrides)>,
"new_fir_freq" : <new period for regular PLI keyframe requests to publishers>,
"new_publishers" : <new cap on the number of concurrent active WebRTC publishers>,
"new_lock_record" : <true|false, whether recording state can only be changed when providing the room secret>,
"permanent" : <true|false, whether the room should be also removed from the config file, default=false>
}
{
"videoroom" : "edited",
"room" : <unique numeric ID>
}
{
"request" : "destroy",
"room" : <unique numeric ID of the room to destroy>,
"secret" : "" ,
"permanent" : <true|false, whether the room should be also removed from the config file, default=false>
}
{
"videoroom" : "destroyed",
"room" : <unique numeric ID>
}
{
"videoroom" : "destroyed",
"room" : <unique numeric ID of the destroyed room>
}
{
"request" : "exists",
"room" : <unique numeric ID of the room to check>
}
{
"videoroom" : "success",
"room" : <unique numeric ID>,
"exists" : <true|false>
}
{
"request" : "allowed",
"secret" : "" ,
"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)
]
}
{
"videoroom" : "success",
"room" : <unique numeric ID>,
"allowed" : [
// Updated, complete, list of allowed tokens (only for enable|add|remove)
]
}
{
"request" : "kick",
"secret" : "" ,
"room" : <unique numeric ID of the room>,
"id" : <unique numeric ID of the participant to kick>
}
{
"videoroom" : "success",
}
{
"request" : "list"
}
{
"videoroom" : "success",
"list" : [ // Array of room objects
{ // Room #1
"room" : <unique numeric ID>,
"description" : "" ,
"pin_required" : <true|false, whether a PIN is required to join this room>,
"is_private" : <true|false, whether this room is 'private' (as in hidden) or not>,
"max_publishers" : <how many publishers can actually publish via WebRTC at the same time>,
"bitrate" : <bitrate cap that should be forced (via REMB) on all publishers by default>,
"bitrate_cap" : <true|false, whether the above cap should act as a limit to dynamic bitrate changes by publishers (optional)>,
"fir_freq" : <how often a keyframe request is sent via PLI/FIR to active publishers>,
"require_pvtid": <true|false, whether subscriptions in this room require a private_id>,
"require_e2ee": <true|false, whether end-to-end encrypted publishers are required>,
"notify_joining": <true|false, whether an event is sent to notify all participants if a new participant joins the room>,
"audiocodec" : "" ,
"videocodec" : "" ,
"opus_fec": <true|false, whether inband FEC must be negotiated (note: only available for Opus) (optional)>,
"video_svc": <true|false, whether SVC must be done for video (note: only available for VP9 right now) (optional)>,
"record" : <true|false, whether the room is being recorded>,
"rec_dir" : "" ,
"lock_record" : <true|false, whether the room recording state can only be changed providing the secret>,
"num_participants" : <count of the participants (publishers, active or not; not subscribers)>
"audiolevel_ext": <true|false, whether the ssrc-audio-level extension must be negotiated or not for new publishers>,
"audiolevel_event": <true|false, whether to emit event to other users about audiolevel>,
"audio_active_packets": <amount of packets with audio level for checkup (optional, only if audiolevel_event is true)>,
"audio_level_average": <average audio level (optional, only if audiolevel_event is true)>,
"videoorient_ext": <true|false, whether the video-orientation extension must be negotiated or not for new publishers>,
"playoutdelay_ext": <true|false, whether the playout-delay extension must be negotiated or not for new publishers>,
"transport_wide_cc_ext": <true|false, whether the transport wide cc extension must be negotiated or not for new publishers>
},
// Other rooms
]
}
{
"request" : "listparticipants",
"room" : <unique numeric ID of the room>
}
{
"videoroom" : "participants",
"room" : <unique numeric ID of the room>,
"participants" : [ // Array of participant objects
{ // Participant #1
"id" : <unique numeric ID of the participant>,
"display" : "" ,
"publisher" : "" ,
"talking" : <true|false, whether user is talking or not (only if audio levels are used)>
},
// Other participants
]
}
{
"request" : "join",
"ptype" : "publisher",
"room" : <unique ID of the room to join>,
"id" : <unique ID to register for the publisher; optional, will be chosen by the plugin if missing>,
"display" : "" ,
"token" : ""
}
{
"videoroom" : "joined",
"room" : <room ID>,
"description" : <description of the room, if available>,
"id" : <unique ID of the participant>,
"private_id" : <a different unique ID associated to the participant; meant to be private>,
"publishers" : [
{
"id" : <unique ID of active publisher #1>,
"display" : "" ,
"streams" : [
{
"type" : ">,
"mindex" : "" ,
"mid" : "" ,
"disabled" : <if true, it means this stream is currently inactive/disabled (and so codec, description, etc. will be missing)>,
"codec" : "" ,
"description" : "" ,
"moderated" : <true if this stream audio has been moderated for this participant>,
"simulcast" : "" ,
"svc" : "" ,
"talking" : <true|false, whether the publisher stream has audio activity or not (only if audio levels are used)>,
},
// Other streams, if any
],
"talking" : <true|false, whether the publisher is talking or not (only if audio levels are used); deprecated, use the stream specific ones>,
},
// Other active publishers
],
"attendees" : [ // Only present when notify_joining is set to TRUE for rooms
{
"id" : <unique ID of attendee #1>,
"display" : ""
},
// Other attendees
]
}
{
"videoroom" : "event",
"room" : <room ID>,
"joining" : {
"id" : <unique ID of the new participant>,
"display" : ""
}
}
{
"request" : "publish",
"audiocodec" : ",
"videocodec" : ",
"bitrate" : <bitrate cap to return via REMB; optional, overrides the global room value if present>,
"record" : <true|false, whether this publisher should be recorded or not; optional>,
"filename" : "" ,
"display" : "" ,
"audio_level_average" : "" ,
"audio_active_packets" : "" ,
"display" : "" ,
"descriptions" : [ // Optional
{
"mid" : "" ,
"description" : ""
},
// Other descriptions, if any
]}
{
"videoroom" : "event",
"configured" : "ok"
}
{
"request" : "configure",
"bitrate" : <bitrate cap to return via REMB; optional, overrides the global room value if present (unless bitrate_cap is set)>,
"keyframe" : <true|false, whether we should send this publisher a keyframe request>,
"record" : <true|false, whether this publisher should be recorded or not; optional>,
"filename" : "" ,
"display" : "" ,
"audio_active_packets" : "" ,
"audio_level_average" : "" ,
"mid" : <mid of the m-line to refer to for this configure request; optional>,
"send" : <true|false, depending on whether the media addressed by the above mid should be relayed or not; optional>,
"descriptions" : [
// Updated descriptions for the published streams; see "publish" for syntax; optional
]
}
{
"videoroom" : "event",
"configured" : "ok"
}
{
"videoroom" : "event",
"room" : <room ID>,
"publishers" : [
{
"id" : <unique ID of the new publisher>,
"display" : "" ,
"streams" : [
{
"type" : ">,
"mindex" : "" ,
"mid" : "" ,
"disabled" : <if true, it means this stream is currently inactive/disabled (and so codec, description, etc. will be missing)>,
"codec" : "" ,
"description" : "" ,
"moderated" : <true if this stream audio has been moderated for this participant>,
"simulcast" : "" ,
"svc" : "" ,
"talking" : <true|false, whether the publisher stream has audio activity or not (only if audio levels are used)>,
},
// Other streams, if any
],
"talking" : <true|false, whether the publisher is talking or not (only if audio levels are used); deprecated, use the stream specific ones>,
}
]
}
{
"request" : "unpublish"
}
{
"videoroom" : "event",
"unpublished" : "ok"
}
{
"videoroom" : "event",
"room" : <room ID>,
"unpublished" : <unique ID of the publisher who unpublished>
}
{
"videoroom" : "event",
"configured" : "ok"
}
{
"videoroom" : <"talking"|"stopped-talking", whether the publisher started or stopped talking>,
"room" : <unique numeric ID of the room the publisher is in>,
"id" : <unique numeric ID of the publisher>,
"audio-level-dBov-avg" : <average value of audio level, 127=muted, 0='too loud'>
}
{
"request" : "rtp_forward",
"room" : <unique numeric ID of the room the publisher is in>,
"publisher_id" : <unique numeric ID of the publisher to relay externally>,
"host" : "" ,
"host_family" : "" ,
"streams" : [
{
"mid" : "" ,
"host" : "" ,
"host_family" : "" ,
"port" : <port to forward the packets to>,
"ssrc" : <SSRC to use to use when forwarding; optional, and only for RTP streams, not data>,
"pt" : <payload type to use when forwarding; optional, and only for RTP streams, not data>,
"rtcp_port" : <port to contact to receive RTCP feedback from the recipient; optional, and only for RTP streams, not data>,
"simulcast" : <true|false, set to true if the source is simulcast and you want the forwarder to act as a regular viewer (single stream being forwarded) or false otherwise (substreams forwarded separately); optional, default=false>,
"port_2" : <if video and simulcasting, port to forward the packets from the second substream/layer to>,
"ssrc_2" : <if video and simulcasting, SSRC to use to use the second substream/layer; optional>,
"pt_2" : <if video and simulcasting, payload type to use the second substream/layer; optional>,
"port_3" : <if video and simulcasting, port to forward the packets from the third substream/layer to>,
"ssrc_3" : <if video and simulcasting, SSRC to use to use the third substream/layer; optional>,
"pt_3" : <if video and simulcasting, payload type to use the third substream/layer; optional>,
},
{
.. other streams, if needed..
}
],
"srtp_suite" : <length of authentication tag (32 or 80); optional>,
"srtp_crypto" : ""
}
{
"videoroom" : "rtp_forward",
"room" : <unique numeric ID, same as request>,
"publisher_id" : <unique numeric ID, same as request>,
"forwarders" : [
{
"stream_id" : <unique numeric ID assigned to this forwarder, if any>,
"type" : ",
"host" : "" ,
"port" : <port this forwarder is streaming to, same as request if configured>,
"local_rtcp_port" : <local port this forwarder is using to get RTCP feedback, if any>,
"remote_rtcp_port" : <remote port this forwarder is getting RTCP feedback from, if any>,
"ssrc" : <SSRC this forwarder is using, same as request if configured>,
"pt" : <payload type this forwarder is using, same as request if configured>,
"substream" : <video substream this video forwarder is relaying, if any>,
"srtp" : <true|false, whether the RTP stream is encrypted (not used for data)>
},
// Other forwarders, if configured
]
}
{
"request" : "stop_rtp_forward",
"room" : <unique numeric ID of the room the publisher is in>,
"publisher_id" : <unique numeric ID of the publisher to update>,
"stream_id" : <unique numeric ID of the RTP forwarder>
}
{
"videoroom" : "stop_rtp_forward",
"room" : <unique numeric ID, same as request>,
"publisher_id" : <unique numeric ID, same as request>,
"stream_id" : <unique numeric ID, same as request>
}
{
"request" : "listforwarders",
"room" : <unique numeric ID of the room>,
"secret" : ""
}
{
"videoroom" : "forwarders",
"room" : <unique numeric ID of the room>,
"publishers" : [ // Array of publishers with RTP forwarders
{ // Publisher #1
"publisher_id" : <unique numeric ID of publisher #1>,
"forwarders" : [ // Array of RTP forwarders
{ // RTP forwarder #1
"stream_id" : <unique numeric ID assigned to this RTP forwarder, if any>,
"type" : ",
"host" : "" ,
"port" : <port this forwarder is streaming to>,
"local_rtcp_port" : <local port this forwarder is using to get RTCP feedback, if any>,
"remote_rtcp_port" : <remote port this forwarder getting RTCP feedback from, if any>,
"ssrc" : <SSRC this forwarder is using, if any>,
"pt" : <payload type this forwarder is using, if any>,
"substream" : <video substream this video forwarder is relaying, if any>,
"srtp" : <true|false, whether the RTP stream is encrypted>
},
// Other forwarders for this publisher
],
},
// Other publishers
]
}
{
"request" : "enable_recording",
"room" : <unique numeric ID of the room>,
"secret" : ""
"record" : <true|false, whether participants in this room should be automatically recorded or not>,
}
参与者通常也可以通过configure请求来更改⾃⼰的录制状态:这样做是为了获得最⼤的灵活性,可能希望单独记录⼀些流,⽽不是全局或⾃动记录⼀些内容,到特定⽂件。
就是说,如果希望确保在启⽤全局录制后参与者不能停⽌其录制,或者在不应该录制该会议室的情况下启动它,那么您应该确保在创建会议室时使⽤lock_record属性,将其设置为true。这样,只有在提供了房间密码的情况下,才能更改录制状态,从⽽确保只有管理员才能执⾏此操作。
最后,您可以使⽤ leave 请求离开会议室。如果您是会议室中的活动发布者,这也将隐式取消你的发布。该leave请求如下所示
{
"request" : "leave"
}
{
"videoroom" : "event",
"leaving" : "ok"
}
{
"videoroom" : "event",
"room" : <room ID>,
"leaving : <unique ID of the participant who left>
}
{
"request" : "join",
"ptype" : "subscriber",
"room" : <unique ID of the room to subscribe in>,
"feed" : <unique ID of the publisher to subscribe to; mandatory>,
"private_id" : <unique ID of the publisher that originated this request; optional, unless mandated by the room configuration>,
"streams" : [
{
"feed" : <unique ID of publisher owning the stream to subscribe to>,
"mid" : ""
// Optionally, simulcast or SVC targets (defaults if missing)
},
// Other streams to subscribe to
]
}
{
"videoroom" : "attached",
"room" : <room ID>,
"streams" : [
{
"mindex" : <unique m-index of this stream>,
"mid" : "" ,
"type" : "" ,
"feed_id" : <unique ID of the publisher originating this stream>,
"feed_mid" : "" ,
"feed_display" : "" ,
"send" : <true|false; whether we configured the stream to relay media>,
"ready" : <true|false; whether this stream is ready to start sending media (will be false at the beginning)>
},
// Other streams in the subscription, if any
]
}
{
"request" : "start"
}
{
"videoroom" : "event",
"started" : "ok"
}
{
"request" : "pause"
}
{
"videoroom" : "event",
"paused" : "ok"
}
{
"request" : "configure",
"mid" : <mid of the m-line to refer to for this configure request; optional>,
"send" : <true|false, depending on whether the mindex media should be relayed or not; optional>,
"substream" : <substream to receive (0-2), in case simulcasting is enabled; optional>,
"temporal" : <temporal layers to receive (0-2), in case simulcasting is enabled; optional>,
"fallback" : <How much time (in us, default 250000) without receiving packets will make us drop to the substream below>,
"spatial_layer" : <spatial layer to receive (0-2), in case VP9-SVC is enabled; optional>,
"temporal_layer" : <temporal layers to receive (0-2), in case VP9-SVC is enabled; optional>,
"audio_level_average" : "" ,
"audio_active_packets" : "" ,
"restart" : <trigger an ICE restart; optional>
}
{
"request" : "switch",
"streams" : [
{
"feed" : <unique ID of the publisher the new source is from>,
"mid" : "" ,
"sub_mid" : ""
},
{
// Other updates, if any
}
]
}
{
"videoroom" : "event",
"switched" : "ok",
"room" : <room ID>,
"changes" : <number of successful changes (may be smaller than the size of the streams array provided in the request)>,
"streams" : [
// Current configuration of the subscription, same format as when subscribing
// Will contain info on all streams, not only those that have been updated
]
}
{
"request" : "leave"
}
{
"videoroom" : "event",
"left" : "ok",
}