snapshot of https://github.com/jitsi/jitsi-videobridge.git @ fcbf741c646bc237d2ed85a1e86910532532b831 (2026-09-15)
This commit is contained in:
305
doc/allocation.md
Normal file
305
doc/allocation.md
Normal file
@@ -0,0 +1,305 @@
|
||||
# Bandwidth Allocation Algorithm
|
||||
|
||||
Bandwidth allocation is the process of selecting the set of layers to forward to a specific endpoint (the "receiver"),
|
||||
or "allocating" the available bandwidth among the available layers. When conditions change, the algorithm is re-run,
|
||||
and the set of forwarded layers is updated according to the new result.
|
||||
|
||||
The overall goal is to provide the most relevant and suitable set of streams to the receiver, given a limited bandwidth.
|
||||
|
||||
## Input
|
||||
### Available bandwidth
|
||||
The available bandwidth (or the Bandwidth Estimation, BWE) is the estimated bandwidth between the bridge and the
|
||||
receiver. It is calculated elsewhere, and is only used as input for bandwidth allocation.
|
||||
|
||||
### Available sources
|
||||
This is the list of streams being sent from the other endpoints in the conference. Streams have multiple layers, and
|
||||
the algorithm selects one layer (or no layers) for each source.
|
||||
|
||||
For example, a simulcast sender can encode its video in 3 different encodings, with 3 different frame rates each. This
|
||||
gives the allocator 9 layers to choose from.
|
||||
|
||||
The list of available sources changes when endpoints join or leave the conference, or when they signal a change in their
|
||||
streams (such as when an endpoint switches from a video camera to screensharing or vice-versa).
|
||||
|
||||
### Receiver-specified settings
|
||||
The following settings are controlled by the receiver, with messages over the "bridge channel".
|
||||
|
||||
#### LastN
|
||||
LastN is the maximum number of video streams that the receiver wants to receive. To effectively stop receiving video
|
||||
(for example to conserve bandwidth), the receiver can set LastN=0.
|
||||
|
||||
#### Selected sources
|
||||
This is a list of sources to be prioritized first, overriding the natural speech activity order of the endpoints which
|
||||
own the sources.
|
||||
|
||||
For example, if the receiver wants to always receive a screensharing source, regardless of who is speaking
|
||||
in the conference, it can "select" this source.
|
||||
|
||||
#### On-stage sources
|
||||
This is a list of sources for which allocation should be prioritized up to a higher resolution (since they are
|
||||
displayed "on stage"). On-stage sources are prioritized higher than selected sources, and in addition:
|
||||
1. Allocation for them is greedy up to the preferred resolution
|
||||
([360p by default](https://github.com/jitsi/jitsi-videobridge/blob/master/jvb/src/main/resources/reference.conf#L40))
|
||||
2. Above the preferred resolution, only frame rates of
|
||||
[at least 30 fps](https://github.com/jitsi/jitsi-videobridge/blob/master/jvb/src/main/resources/reference.conf#L41)
|
||||
are considered.
|
||||
|
||||
#### Video Constraints
|
||||
Video constraints are resolution (`maxHeight`) and frame rate (`maxFrameRate`) constraints for each source. These are
|
||||
"soft" constraints in the sense that the bridge may exceed them in some circumstances (see below).
|
||||
|
||||
When set to a negative number, they indicate no constraints.
|
||||
|
||||
When set to 0, they signal that no video should be forwarded for the associated source, and this is never exceeded.
|
||||
|
||||
When set to a positive number, the algorithm will attempt to select a layer which satisfies the constraints. If no
|
||||
layers satisfy the constraints, and there is sufficient bandwidth, the algorithm will exceed the constraints and
|
||||
select the lowest layer. In practice this is relevant only in the case where a sender does not use simulcast (or SVC),
|
||||
and encodes a single high-resolution stream. Given enough bandwidth, the stream will be forwarded even when the receiver
|
||||
signaled low constraints.
|
||||
|
||||
## Implementation
|
||||
The bandwidth allocation algorithm is implemented in [BandwidthAllocator](https://github.com/jitsi/jitsi-videobridge/blob/master/jvb/src/main/kotlin/org/jitsi/videobridge/cc/allocation/BandwidthAllocator.kt)
|
||||
|
||||
It consists of 3 phases:
|
||||
### 1. Prioritize
|
||||
This phase orders the available sources in the desired way. It starts with sources coming from the endpoints ordered by
|
||||
speech activity (dominant speaker, followed by the previous dominant speaker, etc). Then, it moves the sources from
|
||||
the endpoints which are NOT sending video to the bottom of the list (this is actually implemented in
|
||||
[ConferenceSpeechActivity](https://github.com/jitsi/jitsi-videobridge/blob/master/jvb/src/main/java/org/jitsi/videobridge/ConferenceSpeechActivity.java).
|
||||
Finally, the selected sources are moved to the TOP of the list.
|
||||
|
||||
TODO: Update the algorithm, to only move selected endpoint when they are sending video.
|
||||
|
||||
### 2. Apply LastN
|
||||
This phase disables the video sources in the list that are not among the first `LastN`. Note that the effective
|
||||
`LastN` value comes from the number signaled by the client, potentially also limited by [static](https://github.com/jitsi/jitsi-videobridge/blob/master/jvb/src/main/kotlin/org/jitsi/videobridge/JvbLastN.kt)
|
||||
and [dynamic](https://github.com/jitsi/jitsi-videobridge/blob/master/jvb/src/main/kotlin/org/jitsi/videobridge/load_management/LastNReducer.kt)
|
||||
configuration of the bridge. This is implemented by setting the `maxHeight` constraint to 0.
|
||||
|
||||
The resulting constraints are the "effective" constraints used by the rest of the algorithm. Once calculated, they are
|
||||
announced via an event, so that the sender-side constraints can be applied. Doing this step here, early in the process,
|
||||
allows us to do "aggressive layer suspension" (i.e. set sender-side constraints based on LastN).
|
||||
|
||||
### 3. Allocation
|
||||
The final phase is the actual allocation.
|
||||
|
||||
#### 3.1 Initialize potential layers
|
||||
The first step is to initialize a list of layers to consider for each source. It starts with the list of all layers
|
||||
for the source, and prunes ones which should not be considered:
|
||||
|
||||
A) The ones with resolution and frame rate higher than the constraints
|
||||
|
||||
B) The ones which are inactive (the sending endpoint is currently not transmitting them)
|
||||
|
||||
C) Layers with high resolution but insufficient frame rate, that is at least the [preferred resolution](https://github.com/jitsi/jitsi-videobridge/blob/master/jvb/src/main/resources/reference.conf#L41),
|
||||
and frame rate less than the [preferred frame rate](https://github.com/jitsi/jitsi-videobridge/blob/master/jvb/src/main/resources/reference.conf#L42).
|
||||
For example, with the defaults of preferred resolution 360p and preferred frame rate 30 fps, the following layers will
|
||||
not be considered: 360p/7.5fps, 360p/15fps, 720p/7.5fps, 720p/15fps.
|
||||
|
||||
#### 3.2 Allocation loop
|
||||
It starts with no layers selected for any source, and remaining bandwidth equal to the total available bandwidth.
|
||||
Until there is remaining bandwidth, it loops over the sources in the order obtained in [phase 1](#1.-Prioritize),
|
||||
and tries to `improve()` the layer of each.
|
||||
|
||||
The normal `improve()` step selects the next higher layer if there is sufficient bandwidth. For on-stage sources
|
||||
the `improve()` step works eagerly up to the "preferred" resolution.
|
||||
The preferred resolution [can be configured](https://github.com/jitsi/jitsi-videobridge/blob/master/jvb/src/main/resources/reference.conf#L40).
|
||||
|
||||
# Signaling
|
||||
This section describes the signaling between the client and the bridge that affects bandwidth allocation.
|
||||
|
||||
## Message format
|
||||
|
||||
The receiver's video constraint message is used to signal the preference of the client in regard to which media streams
|
||||
it wants to receive. Usually only a portion of all available videos is displayed on the client. Each video is identified
|
||||
by a source name and each endpoint can send multiple videos. The default format used in jitsi-meet follows a pattern
|
||||
where the first part is the endpoint ID followed by '-v' and the zero-based index of the video source (see the example
|
||||
below).
|
||||
|
||||
```json
|
||||
{
|
||||
"colibriClass": "ReceiverVideoConstraints",
|
||||
"lastN": 2,
|
||||
"selectedSources": ["A-v0", "B-v0"],
|
||||
"onStageSources": ["A-v1","C-v0", "D-v0"],
|
||||
"defaultConstraints": { "maxHeight": 180 },
|
||||
"constraints": {
|
||||
"A-v1": { "maxHeight": 720 },
|
||||
"B-v0": { "maxHeight": 360 }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
All fields are optional. The ones which are included will be updated, and the ones which are not included are not
|
||||
changed.
|
||||
|
||||
The `defaultConstraints` are used for sources not explicitly included in `constraints` (including new sources).
|
||||
|
||||
The initial values are `lastN: -1` (unlimited), `defaultConstraints: {maxHeight: 180}`
|
||||
([configurable](https://github.com/jitsi/jitsi-videobridge/blob/master/jvb/src/main/resources/reference.conf#L38)),
|
||||
and the rest empty.
|
||||
|
||||
### Examples
|
||||
|
||||
#### Stage view (1)
|
||||
Stage view with source `A-v0` in high definition and all other sources in 180p:
|
||||
```json
|
||||
{
|
||||
"colibriClass": "ReceiverVideoConstraints",
|
||||
"onStageSources": ["A-v0"],
|
||||
"defaultConstraints": { "maxHeight": 180 },
|
||||
"constraints": {
|
||||
"A-v0": { "maxHeight": 720 }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Stage view (2)
|
||||
Stage view with source `A-v0` in high definition, `B-v0`, `C-v0`, `D-v0` in 180p and all others disabled:
|
||||
```json
|
||||
{
|
||||
"colibriClass": "ReceiverVideoConstraints",
|
||||
"onStageSources": ["A-v0"],
|
||||
"defaultConstraints": { "maxHeight": 0 },
|
||||
"constraints": {
|
||||
"A-v0": { "maxHeight": 720 },
|
||||
"B-v0": { "maxHeight": 180 },
|
||||
"C-v0": { "maxHeight": 180 },
|
||||
"D-v0": { "maxHeight": 180 }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Stage view (3)
|
||||
Stage view with source `A-v0` in high definition, `B-v0`, `C-v0`, `D-v0` disabled and all others in 180p:
|
||||
```json
|
||||
{
|
||||
"colibriClass": "ReceiverVideoConstraints",
|
||||
"onStageSources": ["A-v0"],
|
||||
"defaultConstraints": { "maxHeight": 180 },
|
||||
"constraints": {
|
||||
"A-v0": { "maxHeight": 720 },
|
||||
"B-v0": { "maxHeight": 0 },
|
||||
"C-v0": { "maxHeight": 0 },
|
||||
"D-v0": { "maxHeight": 0 }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Stage view (4)
|
||||
Stage view with source `A-v0` in high definition and all other sources in 180p, with "D-v0" prioritized higher than
|
||||
the dominant speaker's video source:
|
||||
```json
|
||||
{
|
||||
"colibriClass": "ReceiverVideoConstraints",
|
||||
"onStageEndpoints": ["A-v0"],
|
||||
"selectedEndpoints": ["D-v0"],
|
||||
"defaultConstraints": { "maxHeight": 180 },
|
||||
"constraints": {
|
||||
"A-v0": { "maxHeight": 720 }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Tile view (1)
|
||||
Tile view with all sources in 180p/15fps:
|
||||
```json
|
||||
{
|
||||
"colibriClass": "ReceiverVideoConstraints",
|
||||
"defaultConstraints": { "maxHeight": 180, "maxFrameRate": 15 }
|
||||
}
|
||||
```
|
||||
|
||||
#### Tile view (2)
|
||||
Tile view with all sources in 360p:
|
||||
```json
|
||||
{
|
||||
"colibriClass": "ReceiverVideoConstraints",
|
||||
"defaultConstraints": { "maxHeight": 360 }
|
||||
}
|
||||
```
|
||||
|
||||
#### Tile view (3)
|
||||
Tile view with 180p, sources `A-v0` and `B-v0` prioritized, and sources `C-v0` and `D-v0` disabled:
|
||||
```json
|
||||
{
|
||||
"colibriClass": "ReceiverVideoConstraints",
|
||||
"selectedSources": ["A-v0", "B-v0"],
|
||||
"defaultConstraints": { "maxHeight": 180 },
|
||||
"constraints": {
|
||||
"C-v0": { "maxHeight": 0 },
|
||||
"D-v0": { "maxHeight": 0 }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Tile view (4)
|
||||
Tile view with all sources disabled except `A-v0`, `B-v0`, `C-v0`:
|
||||
```json
|
||||
{
|
||||
"colibriClass": "ReceiverVideoConstraints",
|
||||
"defaultConstraints": { "maxHeight": 0 },
|
||||
"constraints": {
|
||||
"A-v0": { "maxHeight": 180 },
|
||||
"B-v0": { "maxHeight": 180 },
|
||||
"C-v0": { "maxHeight": 180 }
|
||||
}
|
||||
}
|
||||
```
|
||||
#### Multi-stage view (1)
|
||||
With two on-stage sources, and up-to 4 other sources at 180p:
|
||||
```json
|
||||
{
|
||||
"colibriClass": "ReceiverVideoConstraints",
|
||||
"onStageSources": ["A-v0", "B-v0"],
|
||||
"lastN": 6,
|
||||
"defaultConstraints": { "maxHeight": 180 },
|
||||
"constraints": {
|
||||
"A-v0": { "maxHeight": 720 },
|
||||
"B-v0": { "maxHeight": 720 }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Old message format
|
||||
The old format works with endpoint IDs rather than source names. It also uses `selectedEndpoints` and `onStageEndpoints`
|
||||
instead of `selectedSources` and `onStageSources`. All use cases described in the examples above are valid here as
|
||||
well, but the assumption is that every endpoint has only one video source.
|
||||
|
||||
```json
|
||||
{
|
||||
"colibriClass": "ReceiverVideoConstraints",
|
||||
"lastN": 2,
|
||||
"selectedEndpoints": ["A", "B"],
|
||||
"onStageEndpoints": ["C", "D"],
|
||||
"defaultConstraints": { "maxHeight": 180 },
|
||||
"constraints": {
|
||||
"A": { "maxHeight": 720 },
|
||||
"B": { "maxHeight": 360 }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The support for source names vs legacy endpoint ID based format is determined on the ColibriV2 level. The endpoint
|
||||
create request must indicate "source-names" capability on the endpoint that will be using the new format. This is done
|
||||
automatically by Jicofo when multi stream support is enabled in jitsi-meet, but if you're using JVB without Jicofo then
|
||||
remember to do that yourself.
|
||||
|
||||
```xml
|
||||
<iq xmlns='jabber:client' to='jvbbrewery@internal-muc.meet.jitsi/jvb1' id='VFLJ9-10' type='get'>
|
||||
<conference-modify xmlns='jitsi:colibri2' meeting-id='62a5bc4c-c79c-4eab-a071-6740eb549296'>
|
||||
<endpoint xmlns='jitsi:colibri2' id='fefbee3e' create='true' >
|
||||
<capability name='source-names'/> <!--- SOURCE NAME CAPABILITY -->
|
||||
<media type='audio'>
|
||||
...
|
||||
</media>
|
||||
<media type='video'>
|
||||
...
|
||||
</media>
|
||||
<transport ice-controlling='true'/>
|
||||
</endpoint>
|
||||
</conference-modify>
|
||||
</iq>
|
||||
```
|
||||
18
doc/constraints.md
Normal file
18
doc/constraints.md
Normal file
@@ -0,0 +1,18 @@
|
||||
## Video Constraints
|
||||
|
||||
###### Sender video constraints
|
||||
|
||||
The bridge sends the following message to a sender to notify it that resolutions
|
||||
higher than the specified need not be transmitted for a specific video source:
|
||||
|
||||
```
|
||||
{
|
||||
"colibriClass": "SenderSourceConstraints",
|
||||
"sourceName": "endpoint1-v0",
|
||||
"maxHeight": 180
|
||||
}
|
||||
```
|
||||
|
||||
Note that in order to handle portrait-mode video correctly,
|
||||
despite the name `maxHeight`, this parameter is actually used to specify the smaller
|
||||
of the dimensions of the video (which for portrait mode will be its width).
|
||||
36
doc/datachannel-communication.md
Normal file
36
doc/datachannel-communication.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# Messages by COLIBRI class:
|
||||
|
||||
## EndpointMessage:
|
||||
|
||||
|
||||
This type of messages could be used by the clients for sending JSON objects to the other clients in the conference. A client can send a message to specific endpoint or a broadcast message.
|
||||
|
||||
|
||||
|
||||
* The messages processed by Jitsi Videobridge has the following format:
|
||||
|
||||
```
|
||||
{
|
||||
colibriClass: "EndpointMessage",
|
||||
to: `<ENDPOINT-ID>`,
|
||||
msgPayload: `<PAYLOAD>`
|
||||
}
|
||||
```
|
||||
|
||||
`<PAYLOAD>` is valid JSON string.
|
||||
`<ENDPOINT-ID>` is endpoint id of existing participant or `""` for broadcast message.
|
||||
|
||||
* The messages sent by Jitsi Videobridge has the following format:
|
||||
|
||||
|
||||
```
|
||||
{
|
||||
colibriClass: "EndpointMessage",
|
||||
to: `<ENDPOINT-ID>`,
|
||||
from: `<ENDPOINT-ID>`,
|
||||
msgPayload: <PAYLOAD>
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
The only modification made by Jitsi Videobridge before the message is forwarded is adding `from` property to it. The value of this property is the endpoint id of the sender of the message.
|
||||
201
doc/debugging.md
Normal file
201
doc/debugging.md
Normal file
@@ -0,0 +1,201 @@
|
||||
# Introduction
|
||||
|
||||
This document describes some HTTP endpoints that can be useful when debugging jitsi-videobridge. With a few exceptions,
|
||||
these are NOT intended to be used against production systems. Most endpoints return valid JSON which can be fed to e.g. `jq`:
|
||||
```
|
||||
curl http://localhost:8080/debug | jq .
|
||||
```
|
||||
|
||||
# Basic queries
|
||||
|
||||
### Health
|
||||
Returns `200 OK` if the instance is currently healthy, and `4XX/5XX` otherwise.
|
||||
```
|
||||
GET /about/health
|
||||
```
|
||||
|
||||
### Version
|
||||
Returns the currently running version.
|
||||
```
|
||||
GET /about/version
|
||||
```
|
||||
|
||||
### Get Dominant speaker
|
||||
Returns a dominant speaker identification
|
||||
```
|
||||
GET /colibri/v2/conferences/{meetingId}/dominant-speaker-identification
|
||||
```
|
||||
|
||||
|
||||
### Overall statistics
|
||||
Returns overall bridge statistics. These include number of current and total conferences and endpoints, number of packets/bytes received/sent, current packet rate and bit rate. They are generally suitable for storing as timeseries in order to monitor a service.
|
||||
```
|
||||
GET /colibri/stats
|
||||
```
|
||||
|
||||
|
||||
# Detailed debug state
|
||||
The following can be used to get very detailed state of running conferences and endpoints.
|
||||
|
||||
### List conferences
|
||||
This includes a list of all conferences and their endpoints, but not the full state.
|
||||
```
|
||||
GET /debug
|
||||
```
|
||||
|
||||
### List all conferences with full state
|
||||
This includes the full state of all conferences and their endpoints. The output can be substantial (~25KB per endpoint).
|
||||
```
|
||||
GET /debug?full=true
|
||||
```
|
||||
|
||||
## List a specific conference with full state
|
||||
This includes the full state of a specific conference and its endpoints. The output can be substantial (~25KB per endpoint).
|
||||
The full output can be suspended (leaving just the list of endpoints) by adding `?full=false`.
|
||||
```
|
||||
GET /debug/CONFERENCE_ID
|
||||
```
|
||||
|
||||
## Get full state for an endpoint
|
||||
This includes the full state of a specific endpoint in a specific conference.
|
||||
```
|
||||
GET /debug/CONFERENCE_ID/ENDPOINT_ID
|
||||
```
|
||||
|
||||
|
||||
# Global debug options and statistic features
|
||||
These are features that affect the entire bridge (as opposed to a single endpoint or conference).
|
||||
|
||||
### Payload verification
|
||||
This mode enables verification of the RTP payload between each step of the packet pipeline.
|
||||
This is very CPU intensive and disabled by default (it is only useful for testing new code).
|
||||
|
||||
Enable:
|
||||
```
|
||||
POST /debug/stats/jvb/payload-verification/true
|
||||
```
|
||||
|
||||
Disable:
|
||||
```
|
||||
POST /debug/stats/jvb/payload-verification/false
|
||||
```
|
||||
|
||||
Query:
|
||||
```
|
||||
GET /debug/stats/jvb/payload-verification
|
||||
```
|
||||
|
||||
### Pipeline statistics
|
||||
This keeps track of processing delay, number of discarded packets,
|
||||
number of packets by various types, etc. from each Node in the packet
|
||||
processing pipeline. The data is organized by Node type. This has low overhead
|
||||
and is enabled by default. Note that the data does not update in real-time, but
|
||||
only when endpoints expire.
|
||||
|
||||
Enable:
|
||||
```
|
||||
POST /debug/stats/jvb/node-stats/true
|
||||
```
|
||||
|
||||
Disable:
|
||||
```
|
||||
POST /debug/stats/jvb/node-stats/false
|
||||
```
|
||||
Query:
|
||||
```
|
||||
GET /debug/stats/jvb/node-stats
|
||||
```
|
||||
|
||||
### Memory pool statistics
|
||||
These include current size, number of requests, allocation rates, etc. for the application memory pools. This is disabled by default.
|
||||
|
||||
Enable:
|
||||
```
|
||||
POST /debug/stats/jvb/pool-stats/true
|
||||
```
|
||||
|
||||
Disable:
|
||||
```
|
||||
POST /debug/stats/jvb/pool-stats/false
|
||||
```
|
||||
Query:
|
||||
```
|
||||
GET /debug/stats/jvb/pool-stats
|
||||
```
|
||||
|
||||
### Packet queue statistics
|
||||
This keeps track of the number of dropped packets and exception caught in the
|
||||
various packet queues. It is enabled by default.
|
||||
|
||||
Enable:
|
||||
```
|
||||
POST /debug/stats/jvb/queue-stats/true
|
||||
```
|
||||
|
||||
Disable:
|
||||
```
|
||||
POST /debug/stats/jvb/queue-stats/false
|
||||
```
|
||||
|
||||
Query:
|
||||
```
|
||||
GET /debug/stats/jvb/queue-stats
|
||||
```
|
||||
|
||||
### Packet transit time statistics
|
||||
This keeps track of the overall transit time for RTP/RTCP packets (average,
|
||||
max, and a distribution), as well as the jitter introduced in processing. It
|
||||
is always enabled.
|
||||
|
||||
Query:
|
||||
```
|
||||
GET /debug/stats/jvb/transit-stats
|
||||
```
|
||||
|
||||
### Task pool stats
|
||||
This keeps track of statistics for the various task pools (CPU, IO, scheduled).
|
||||
It is always enabled.
|
||||
|
||||
Query:
|
||||
```
|
||||
GET /debug/stats/jvb/task-pool-stats
|
||||
```
|
||||
|
||||
### XMPP Delay stats
|
||||
This keeps track of the response time for requests received over XMPP.
|
||||
|
||||
Query:
|
||||
```
|
||||
GET /debug/stats/jvb/xmpp-delay-stats
|
||||
```
|
||||
|
||||
### Node tracing
|
||||
This adds an entry to the stack trace from each Node in the packet processing pipeline.
|
||||
|
||||
Enable:
|
||||
```
|
||||
POST /debug/stats/jvb/node-tracing/true
|
||||
```
|
||||
|
||||
Disable:
|
||||
```
|
||||
POST /debug/stats/jvb/node-tracing/false
|
||||
```
|
||||
|
||||
# Endpoint-specific debug options and features
|
||||
These are features that can be enabled for a specific endpoint in a specific conference.
|
||||
|
||||
### Saving RTP/RTCP in PCAP
|
||||
This enables saving the RTP and RTCP traffic sent/received from a specific endpoint to a PCAP file in `/tmp/`.
|
||||
The use of this feature is disabled by default, and the bridge needs to be explicitly configured to
|
||||
allow it by setting `jmt.debug.pcap.enabled=true` in `/etc/jitsi/videobridge/jvb.conf`.
|
||||
|
||||
Enable:
|
||||
```
|
||||
POST /debug/features/endpoint/CONFERENCE_ID/ENDPOINT_ID/pcap-dump/true
|
||||
```
|
||||
|
||||
Disable:
|
||||
```
|
||||
POST /debug/features/endpoint/CONFERENCE_ID/ENDPOINT_ID/pcap-dump/false
|
||||
```
|
||||
19
doc/health-checks.md
Normal file
19
doc/health-checks.md
Normal file
@@ -0,0 +1,19 @@
|
||||
The REST API allows querying Videobridge whether it deems itself in a healthy state (i.e. the application is operational and the functionality it provides should perform as expected) at the time of the query or not. Videobridge performs periodic internal tests, and returns the latest result in response to requests to the `/about/health` endpoint.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>HTTP Method</th>
|
||||
<th>Resource</th>
|
||||
<th>Response</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>GET</code></td>
|
||||
<td><code>/about/health</code></td>
|
||||
<td>
|
||||
<ul>
|
||||
<li><code>200 OK</code> The service is healthy. The response is with <code>Content-Type: application/json</code> but no JSON value is provided i.e. <code>Content-Length: 0</code>.</li>
|
||||
<li><code>500 Internal Server Error</code> or any other <code>5xx</code> status code if Videobridge determined that it is in an unhealthy state.</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
66
doc/muc.md
Normal file
66
doc/muc.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# Intro
|
||||
When the XMPP API is enabled jitsi-videobridge uses an XMPP client connection and advertises presence in a Multi-User
|
||||
Chat (MUC) room.
|
||||
|
||||
With this mode a jitsi-videobridge instance can connect to a set of XMPP servers, and new servers
|
||||
can be added [at runtime](https://github.com/jitsi/jitsi-videobridge/blob/master/doc/rest-muc-client.md).
|
||||
|
||||
# XMPP server configuration
|
||||
The XMPP server can be provisioned with a single user account to be shared between all jitsi-videobridge instances that
|
||||
connect to it. For prosody this can be done using:
|
||||
|
||||
```
|
||||
prosodyctl register jvb $DOMAIN $PASSWORD
|
||||
```
|
||||
|
||||
We recommend using a separate XMPP domain, not accessible by anonymous users.
|
||||
See the [jitsi-meet-prosody postinst
|
||||
script](https://github.com/jitsi/jitsi-meet/blob/master/debian/jitsi-meet-prosody.postinst)
|
||||
for a full example. It is also possible to use a completely separate XMPP server accessible only to jitsi-videobridge
|
||||
and jicofo (not publicly accessible at all).
|
||||
|
||||
# Jicofo configuration
|
||||
To make use of the MUC mode in the bridge, jicofo needs to be configured to
|
||||
join the same MUC. To do this set `jicofo.bridge.brewery-jid` to the MUC address in `jicofo.conf`.
|
||||
|
||||
# Videobridge configuration
|
||||
To enable the MUC mode add the following to the `videobridge` section of the config file:
|
||||
```
|
||||
stats {
|
||||
# Enable broadcasting stats/presence in a MUC
|
||||
enabled = true
|
||||
transports = [
|
||||
{ type = "muc" }
|
||||
]
|
||||
}
|
||||
|
||||
apis {
|
||||
xmpp-client {
|
||||
configs {
|
||||
# Connect to the first XMPP server
|
||||
xmpp-server-1 {
|
||||
hostname="example.net"
|
||||
domain = "auth.example.net"
|
||||
username = "jvb"
|
||||
password = "$PASSWORD"
|
||||
muc_jids = "JvbBrewery@internal.auth.example.net"
|
||||
# The muc_nickname must be unique across all jitsi-videobridge instances
|
||||
muc_nickname = "unique-instance-id"
|
||||
# disable_certificate_verification = true
|
||||
}
|
||||
# Connect to a second XMPP server
|
||||
xmpp-server-2 {
|
||||
hostname="another.example.net"
|
||||
domain = "auth.example.net"
|
||||
username = "jvb"
|
||||
password = "$PASSWORD"
|
||||
muc_jids = "JvbBrewery@internal.auth.example.net"
|
||||
# The muc_nickname must be unique across all jitsi-videobridge instances
|
||||
muc_nickname = "unique-instance-id2"
|
||||
# disable_certificate_verification = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
41
doc/network-configuration.md
Normal file
41
doc/network-configuration.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Network Configuration
|
||||
|
||||
## IPv6 Configuration
|
||||
|
||||
JVB supports IPv6 in dual-stack (IPv4 + IPv6) environments.
|
||||
To enable it, add the following to your `jvb.conf`:
|
||||
```hocon
|
||||
ice4j {
|
||||
harvest {
|
||||
use-ipv6 = true
|
||||
use-link-local-addresses = false
|
||||
mapping {
|
||||
stun {
|
||||
addresses = [ "your-stun-server:3478" ]
|
||||
}
|
||||
static-mappings = [
|
||||
{
|
||||
local-address = "YOUR_PRIVATE_IPV4"
|
||||
public-address = "YOUR_PUBLIC_IPV4"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Notes
|
||||
- Jitsi Web and the Videobridge can have different IPv6 addresses
|
||||
- When IPv6 is enabled, a UDP6 listener will open on port 10000
|
||||
|
||||
### Verifying ICE Candidates
|
||||
To confirm correct candidates are advertised, enable verbose logging in `/etc/jitsi/videobridge/logging.properties`:
|
||||
```
|
||||
org.jitsi.videobridge.xmpp.XmppConnection.level=ALL
|
||||
```
|
||||
|
||||
Then grep the logs for `SENT` to inspect the ICE candidates being sent.
|
||||
|
||||
### Related Issues
|
||||
- [#1722](https://github.com/jitsi/jitsi-videobridge/issues/1722)
|
||||
|
||||
86
doc/relay.md
Normal file
86
doc/relay.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# Setting up relays (cascaded bridges)
|
||||
|
||||
### Relays
|
||||
Relays (aka secure octo) use ICE and DTLS/SRTP between each pair of bridges, so a secure
|
||||
network is not required. It uses and requires either SCTP or colibri websockets for the
|
||||
bridge-bridge connections.
|
||||
|
||||
## Jitsi Videobridge configuration
|
||||
|
||||
### Relay configuration
|
||||
Relays can be configured with the following properties in `/etc/jitsi/videobridge/jvb.conf` (also see
|
||||
[reference.conf](https://github.com/jitsi/jitsi-videobridge/blob/master/jvb/src/main/resources/reference.conf#L132)).
|
||||
```
|
||||
videobridge {
|
||||
relay {
|
||||
enabled=true
|
||||
region="region1"
|
||||
relay-id="unique-id-of-the-jitsi-videobridge-instance"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Legacy configuration is detected and automatically adapted, so no configuration changes are necessary when upgrading.
|
||||
|
||||
Relays require colibri websockets for the bridge-to-bridge connections, which can be enabled as described in
|
||||
[this document](https://github.com/jitsi/jitsi-videobridge/blob/master/doc/web-sockets.md). Note that the `colibri-relay-ws`
|
||||
endpoints also need to be proxied.
|
||||
|
||||
## Jicofo configuration
|
||||
Octo needs to be enabled, and a suitable bridge selection strategy needs to be configured in `/etc/jitsi/jicofo/jicofo.conf`:
|
||||
|
||||
```
|
||||
jicofo {
|
||||
bridge {
|
||||
selection-strategy = RegionBasedBridgeSelectionStrategy
|
||||
}
|
||||
octo {
|
||||
enabled = true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `RegionBasedBridgeSelectionStrategy` matches the region of the clients to
|
||||
the region of the Jitsi Videobridge instances. That is, it always attempts to select a bridge
|
||||
in the region of the client.
|
||||
|
||||
The `SplitBridgeSelectionStrategy` can be used for testing. It tries to select a new bridge
|
||||
for each client, regardless of the regions. This is useful while testing, because you can
|
||||
verify that Octo works before setting up the region configuration for the clients.
|
||||
|
||||
*Important note*: Jicofo will not mix bridges with different versions in the same conference. Even with
|
||||
`SplitBridgeSelectionStrategy` if the bridges have different versions only bridges with the same version will be used.
|
||||
To prevent this behavior (for testing purposes only) set `jicofo.ocfo.allow-mixed-versions=true` in `jicofo.conf`.
|
||||
|
||||
## Debugging
|
||||
Jicofo's debug interface can be used for troubleshooting.
|
||||
|
||||
To list the bridges available to jicofo (with their versions, regions, etc):
|
||||
```commandline
|
||||
curl "http://localhost:8888/debug" | jq .bridge_selector
|
||||
```
|
||||
|
||||
To list currently running conferences:
|
||||
```commandline
|
||||
curl "http://localhost:8888/debug" | jq .focus_manager
|
||||
```
|
||||
|
||||
To list the full state of a conference (get actual conference ID with the command above, escaping the '@' sign):
|
||||
```commandline
|
||||
curl "http://localhost:8888/debug/conference/test\@conference.example.com" | jq .
|
||||
```
|
||||
|
||||
Look under `colibri_session_manager` for the different bridge sessions.
|
||||
|
||||
|
||||
## Configuring client regions
|
||||
Clients learn about the region that they are in via the value of
|
||||
`config.deploymentInfo.userRegion`. Thus, in order for relays to actually work
|
||||
for geolocation, `config.js` must be served with the correct values. The best
|
||||
way to implement this is outside the scope of this document, and it depends on
|
||||
the environment in which Jitsi Meet is installed.
|
||||
|
||||
One easy solution can be to set the variable based on the domain name, and then
|
||||
access the conference through the desired domain name, e.g. use
|
||||
`us-east.jitsi.example.com`, `us-west.jitsi.example.com`,
|
||||
`eu.jitsi.example.com` and have them serve custom versions of `config.js`.
|
||||
315
doc/rest-colibri2.md
Normal file
315
doc/rest-colibri2.md
Normal file
@@ -0,0 +1,315 @@
|
||||
# Introduction
|
||||
|
||||
This document describes the Colibri2 REST APIs
|
||||
|
||||
See [this document](rest.md) for how to configure the HTTP(S) interfaces of jitsi-videobridge.
|
||||
|
||||
We envision using the HTTP/JSON version of the colibri2 protocol you can see some examples [here](https://github.com/jitsi/jitsi-xmpp-extensions/blob/master/src/test/kotlin/org/jitsi/xmpp/extensions/colibri2/json/Colibri2JSONSerializerTest.kt).
|
||||
|
||||
# Implementation
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>HTTP Method</th>
|
||||
<th>Resource</th>
|
||||
<th>Response</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>GET</td>
|
||||
<td>/colibri/v2/conferences/{meetingId}/dominant-speaker-identification</td>
|
||||
<td>
|
||||
200 OK with JSON objects which represents <code>endpointsBySpeechActivity</code>,<code>dominantEndpoint</code>, <code>endpointsInLastNOrder</code>,<code> dominantSpeakerIdentification</code> <br />
|
||||
For example:
|
||||
<pre>
|
||||
{
|
||||
"endpointsBySpeechActivity": [
|
||||
"79f0273d"
|
||||
],
|
||||
"dominantSpeakerIdentification": null,
|
||||
"endpointsInLastNOrder": [
|
||||
"79f0273d"
|
||||
],
|
||||
"dominantEndpoint": "null"
|
||||
}</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>POST</td>
|
||||
<td>/colibri/v2/conferences/</td>
|
||||
<td>
|
||||
200 OK with a JSON object which represents the created conference if the request was with <code>Content-Type: application/json</code> and was a JSON object which
|
||||
consist field like <code> meeting-id</code>, <code>endpoints</code>, media types, media payloads<br />
|
||||
See the test example
|
||||
<a href="https://github.com/jitsi/jitsi-xmpp-extensions/blob/master/src/test/kotlin/org/jitsi/xmpp/extensions/colibri2/json/Colibri2JSONSerializerTest.kt">
|
||||
Colibri2JSONSerializerTest
|
||||
</a> <br />
|
||||
For example, a request could look like:
|
||||
<pre>
|
||||
{
|
||||
"meeting-id":"beccf2ed-5441-4bfe-96d6-f0f3a6796378",
|
||||
"name":"hardencounterssinkright@muc.meet.jitsi",
|
||||
"create":true,
|
||||
"endpoints":[
|
||||
{
|
||||
"create":true,
|
||||
"id":"79f0273d",
|
||||
"stats-id":"Garett-w1o",
|
||||
"muc-role":"moderator",
|
||||
"medias":[
|
||||
{
|
||||
"type":"audio",
|
||||
"payload-types":[
|
||||
{
|
||||
"name": "red", "id": "112", "channels": "2", "clockrate": "48000",
|
||||
"parameters": { "null": "111/111" }
|
||||
},
|
||||
{
|
||||
"name": "opus", "id": "111", "channels": "2", "clockrate": "48000",
|
||||
"parameters": {"useinbandfec": "1", "minptime": "10" },
|
||||
"rtcp-fbs": [{"type": "transport-cc"}]
|
||||
}
|
||||
],
|
||||
"rtp-hdrexts":[
|
||||
{ "uri":"urn:ietf:params:rtp-hdrext:ssrc-audio-level", "id":1 },
|
||||
{ "uri":"http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01", "id":5 }
|
||||
],
|
||||
"extmap-allow-mixed":true
|
||||
},
|
||||
{
|
||||
"type": "video",
|
||||
"payload-types":[
|
||||
{
|
||||
"name": "VP8", "id": "100", "clockrate": "90000",
|
||||
"parameters": {"x-google-start-bitrate": "800"},
|
||||
"rtcp-fbs":[
|
||||
{ "type": "ccm", "subtype": "fir" },
|
||||
{ "type": "nack" },
|
||||
{ "type": "nack", "subtype": "pli" },
|
||||
{ "type": "transport-cc" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "VP9", "id": "101", "clockrate": "90000",
|
||||
"parameters": {"x-google-start-bitrate": "800"},
|
||||
"rtcp-fbs":[
|
||||
{ "type": "ccm", "subtype": "fir" },
|
||||
{ "type": "nack" },
|
||||
{ "type": "nack", "subtype": "pli" },
|
||||
{ "type": "transport-cc" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"rtp-hdrexts":[
|
||||
{ "uri":"http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time", "id":3 },
|
||||
{ "uri":"http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01", "id":5 }
|
||||
],
|
||||
"extmap-allow-mixed":true
|
||||
}
|
||||
],
|
||||
"transport": { "ice-controlling": true },
|
||||
"capabilities": [ "source-names" ]
|
||||
}
|
||||
],
|
||||
"connects": [
|
||||
{ "url": "wss://example.com/audio", "protocol": "mediajson", "type": "transcriber", "audio": true },
|
||||
{ "url": "wss://example.com/video", "protocol": "mediajson", "type": "recorder", "video": true }
|
||||
]
|
||||
}</pre>
|
||||
|
||||
The respective response could look like:
|
||||
|
||||
<pre>
|
||||
{
|
||||
"endpoints": [
|
||||
{
|
||||
"id": "79f0273d",
|
||||
"transport": {
|
||||
"transport": {
|
||||
"candidates": [
|
||||
{
|
||||
"generation": "0",
|
||||
"component": "1",
|
||||
"protocol": "udp",
|
||||
"port": "10000",
|
||||
"ip": "172.18.0.4",
|
||||
"foundation": "1",
|
||||
"id": "5bbb5d5e101f870f0ffffffffdf286239",
|
||||
"priority": "2130706431",
|
||||
"type": "host",
|
||||
"network": "0"
|
||||
},
|
||||
{
|
||||
"generation": "0",
|
||||
"rel-port": "10000",
|
||||
"component": "1",
|
||||
"protocol": "udp",
|
||||
"port": "10000",
|
||||
"ip": "192.168.1.1",
|
||||
"foundation": "2",
|
||||
"id": "56f8f898101f870f0fffffffff3be6336",
|
||||
"rel-addr": "172.18.0.4",
|
||||
"priority": "1694498815",
|
||||
"type": "srflx",
|
||||
"network": "0"
|
||||
},
|
||||
{
|
||||
"generation": "0",
|
||||
"rel-port": "10000",
|
||||
"component": "1",
|
||||
"protocol": "udp",
|
||||
"port": "10000",
|
||||
"ip": "152.58.154.133",
|
||||
"foundation": "2",
|
||||
"id": "c6ac5101f870f0ffffffffcb50fcba",
|
||||
"rel-addr": "172.18.0.4",
|
||||
"priority": "1694498815",
|
||||
"type": "srflx",
|
||||
"network": "0"
|
||||
}
|
||||
],
|
||||
"xmlns": "urn:xmpp:jingle:transports:ice-udp:1",
|
||||
"ufrag": "26ant1ioqu7qnr",
|
||||
"rtcp-mux": true,
|
||||
"pwd": "9q8uj7tg6j4rc4i6ulc1pmsq9",
|
||||
"web-sockets": [
|
||||
"wss://localhost:8443/colibri-ws/172.18.0.4/7e441eda3701676e/79f0273d?pwd=9q8uj7tg6j4rc4i6ulc1pmsq9"
|
||||
],
|
||||
"fingerprints": [
|
||||
{
|
||||
"fingerprint": "F1:05:72:F8:F3:F4:B4:65:5B:9A:FC:81:24:11:23:78:D5:42:54:B1:F2:66:2F:82:CC:2B:01:1C:DB:98:BE:C0",
|
||||
"setup": "actpass",
|
||||
"hash": "sha-256"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"sources": [
|
||||
{
|
||||
"ssrc": 3191927963,
|
||||
"name": "jvb-a0"
|
||||
}
|
||||
],
|
||||
"id": "jvb-a0",
|
||||
"type": "audio"
|
||||
},
|
||||
{
|
||||
"sources": [
|
||||
{
|
||||
"ssrc": 1863439907,
|
||||
"name": "jvb-v0"
|
||||
}
|
||||
],
|
||||
"id": "jvb-v0",
|
||||
"type": "video"
|
||||
}
|
||||
]
|
||||
}</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>PATCH</td>
|
||||
<td>/colibri/v2/conferences/{mettingId}</td>
|
||||
<td>
|
||||
Expire conference <br />
|
||||
200 OK which represents success. <br />
|
||||
For example:
|
||||
<pre>
|
||||
The Request body to expire conference:
|
||||
{
|
||||
"expire":true
|
||||
}
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>PATCH</td>
|
||||
<td>/colibri/v2/conferences/{mettingId}</td>
|
||||
<td>
|
||||
200 OK which represents success. <br />
|
||||
Here, I am doing it for
|
||||
<a href="https://github.com/jitsi/jitsi-xmpp-extensions/blob/master/src/test/kotlin/org/jitsi/xmpp/extensions/colibri2/json/Colibri2JSONSerializerTest.kt#L326">
|
||||
Conference-modified with transport for an endpoint and feedback sources
|
||||
</a> <br />
|
||||
In the same way you can do it for
|
||||
<a href="https://github.com/jitsi/jitsi-xmpp-extensions/blob/master/src/test/kotlin/org/jitsi/xmpp/extensions/colibri2/json/Colibri2JSONSerializerTest.kt#L388C17-L388C59">
|
||||
Update endpoint with transport and sources
|
||||
</a> <br />
|
||||
For example, a request could look like:
|
||||
<pre>
|
||||
{
|
||||
"endpoints": [
|
||||
{
|
||||
"id":"79f0273e",
|
||||
"transport": {
|
||||
"transport": {
|
||||
"candidates": [
|
||||
{
|
||||
"generation": "0",
|
||||
"rel-port": "9",
|
||||
"component": "1",
|
||||
"protocol": "udp",
|
||||
"port": "10000",
|
||||
"ip": "129.80.210.199",
|
||||
"foundation": "2",
|
||||
"id": "653aa1ba295b62480ffffffffdc52c0d9",
|
||||
"rel-addr": "0.0.0.0",
|
||||
"priority": "1694498815",
|
||||
"type": "srflx",
|
||||
"network": "0"
|
||||
}
|
||||
],
|
||||
"xmlns": "urn:xmpp:jingle:transports:ice-udp:1",
|
||||
"ufrag": "2ivqh1fvtf0l3h",
|
||||
"rtcp-mux": true,
|
||||
"pwd": "1a5ejbent91k6io6a3fauikg22",
|
||||
"web-sockets": [
|
||||
"wss://beta-us-ashburn-1-global-2808-jvb-83-102-26.jitsi.net:443/colibri-ws/default-id/3d937bbdf97a23e0/79f0273e?pwd=1a5ejbent91k6io6a3fauikg22"
|
||||
],
|
||||
"fingerprints": [
|
||||
{
|
||||
"fingerprint": "2E:CC:85:71:32:5B:B5:60:64:C8:F6:7B:6D:45:D4:34:2B:51:A0:06:B5:EA:2F:84:BC:7B:64:1F:A3:0A:69:23",
|
||||
"setup": "actpass",
|
||||
"hash": "sha-256",
|
||||
"cryptex": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "audio",
|
||||
"id": "jvb-a0",
|
||||
"sources": [
|
||||
{ "ssrc":411312308, "name": "jvb-a0", "parameters": { "msid": "mixedmslabel mixedlabelaudio0" } }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "video",
|
||||
"id": "jvb-v0",
|
||||
"sources": [
|
||||
{ "ssrc":3929652146, "name": "jvb-v0", "parameters": { "msid": "mixedmslabel mixedlabelvideo0" } }
|
||||
]
|
||||
}
|
||||
]
|
||||
}</pre>
|
||||
|
||||
The respective response could look like:
|
||||
|
||||
<pre>
|
||||
{
|
||||
"endpoints": [
|
||||
{
|
||||
"id": "79f0273e"
|
||||
}
|
||||
]
|
||||
}</pre>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
34
doc/rest-muc-client.md
Normal file
34
doc/rest-muc-client.md
Normal file
@@ -0,0 +1,34 @@
|
||||
The configuration for the XMPP client connections that jitsi-videobridge uses can be modified at run time using REST calls to `/colibri/muc-client/`.
|
||||
|
||||
# Adding an XMPP client connection
|
||||
A new XMPP client connection (i.e. a MucClient) can be added by posting a JSON which contains its configuration to `/colibri/muc-client/add`:
|
||||
```
|
||||
{
|
||||
"id": "new-client-connection",
|
||||
"domain":"xmpp.example.com",
|
||||
"hostname":"10.0.0.1",
|
||||
"username":"xmpp-username",
|
||||
"password":"xmpp-password",
|
||||
"muc_jids":"JvbBrewery@conference.xmpp.example.com",
|
||||
"muc_nickname":"unique-resource",
|
||||
"disable_certificate_verification":"false"
|
||||
}
|
||||
```
|
||||
|
||||
If a configuration with the specified ID already exists the behavior depends on whether the `hostname`, `port`,
|
||||
`domain` and `username` fields match the existing client. If they match no changes are made, otherwise the existing
|
||||
`MucClient` is removed and a new one is added.
|
||||
|
||||
# Removing an XMPP client connection
|
||||
An XMPP client connection (i.e. a MucClient) can be removed by posting a JSON which contains its ID to `/colibri/muc-client/remove`:
|
||||
```
|
||||
{
|
||||
"id": "new-client-connection"
|
||||
}
|
||||
```
|
||||
|
||||
The request will be successful (return 200) if an XMPP client connection was removed.
|
||||
|
||||
|
||||
# Listing XMPP client connections
|
||||
IDs of previously added XMPP client connections can be listed using a GET call to `/colibri/muc-client/list`.
|
||||
61
doc/rest.md
Normal file
61
doc/rest.md
Normal file
@@ -0,0 +1,61 @@
|
||||
Introduction
|
||||
==============
|
||||
Jitsi-videobridge supports two HTTP(S) interfaces, a _public_ and a _private_ one.
|
||||
The two interfaces use different ports. The _private_ interface exposes
|
||||
HTTP endpoints which are not meant to be publicly accessible (but might be used
|
||||
by other components of the infrastructure, e.g. a signaling server), such as:
|
||||
|
||||
* The [COLIBRI control interface](rest-colibri2.md) (```/colibri/```)
|
||||
* The health-check interface (```/about/health```)
|
||||
* The version interface (```/about/version```)
|
||||
|
||||
The _public_ interface is used for Colibri Web Sockets that clients connect to.
|
||||
|
||||
Configuration
|
||||
==============
|
||||
|
||||
The following configuration properties can be added to the jitsi-videobridge configuration file (whichever file is
|
||||
passed to `-Dconfig.file` when running the bridge, usually `/etc/jitsi/videobridge/jvb.conf`) to control the behavior
|
||||
of the HTTP interfaces.
|
||||
|
||||
For the _private_ interface, use the following block and values:
|
||||
|
||||
```hocon
|
||||
videobridge {
|
||||
apis {
|
||||
rest {
|
||||
enabled = true
|
||||
}
|
||||
}
|
||||
http-servers {
|
||||
private {
|
||||
// The port for the private HTTP interface (or -1 to disable it). Defaults to 8080.
|
||||
port = <Number>
|
||||
// The port for the private HTTP interface if TLS is to be used (or -1 to disable). Defaults to 8443.
|
||||
tls-port = <Number>
|
||||
// The address on which the server will listen
|
||||
host = <String>
|
||||
// The file path to the keystore to be used with HTTPS for the private interface. If this is not specified,
|
||||
// HTTPS is disabled for the private interface
|
||||
key-store-path = <String (path to key store)>
|
||||
// The password to be used by the SslContextFactory when HTTPS is used
|
||||
key-store-password = <String>
|
||||
// Whether or not client certificate authentication is to be required when
|
||||
// HTTPS is used
|
||||
need-client-auth: <Boolean>
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The _public_ interface uses the same values, but under a different scope:
|
||||
|
||||
```hocon
|
||||
videobridge {
|
||||
http-servers {
|
||||
public {
|
||||
// Same values as above
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
129
doc/statistics.md
Normal file
129
doc/statistics.md
Normal file
@@ -0,0 +1,129 @@
|
||||
Introduction
|
||||
============
|
||||
Jitsi Videobridge exports statistics/metrics as key-value pairs in three ways: in a custom JSON format, as Prometheus
|
||||
metrics and as periodic reports published in an XMPP MUC.
|
||||
|
||||
# REST
|
||||
The statistics are available through the `/colibri/stats` endpoint on the [private REST interface](rest.md)
|
||||
(if it has been enabled) in JSON format:
|
||||
```json
|
||||
{
|
||||
"key": "value"
|
||||
}
|
||||
```
|
||||
|
||||
Note that the report itself is generated periodically and a cached version is returned. The period defaults to 5 seconds
|
||||
and can be configured with the `videobridge.stats.interval` property in `jvb.conf`.
|
||||
|
||||
# Prometheus
|
||||
Metrics are exposed in a Prometheus/openmetrics format at `/metrics` on the private HTTP interface. Not all metrics are
|
||||
currently available in this format, and improving this is a work in progress.
|
||||
```commandline
|
||||
# Query prometheus metrics in openmetrics format
|
||||
curl 0:8080/metrics -H 'Accept: application/openmetrics-text'
|
||||
|
||||
# Query prometheus metrics in 004 format
|
||||
curl 0:8080/metrics -H 'Accept: text/plain; version=0.0.4;'
|
||||
|
||||
# Query prometheus metrics in a JSON key-value format
|
||||
curl 0:8080/metrics -H 'Accept: application/json'
|
||||
```
|
||||
|
||||
Note: Conference size distribution metrics (by total endpoints, by audio senders, and by video senders) are available as
|
||||
Prometheus histograms (`conferences_by_size`, `conferences_by_audio_sender`, `conferences_by_video_sender`) but are not
|
||||
exposed via the JSON `/colibri/stats` endpoint.
|
||||
|
||||
# XMPP MUC
|
||||
The statistics can also be published periodically via XMPP (which allows jicofo to monitor a set of bridges and perform
|
||||
load balancing, or allows an application to monitor the MUC and collect metrics from multiple bridges). In this case the
|
||||
key-value pairs are represented in XML format with a `stats` element like this:
|
||||
```xml
|
||||
<stats xmlns=' http://jitsi.org/protocol/colibri'>
|
||||
<stat value='value' name='key'/>
|
||||
</stats>
|
||||
```
|
||||
|
||||
By default, statistics are pushed every 5 seconds and this can be configured in `jvb.conf` with the
|
||||
[`videobridge.apis.xmpp-client.presence-interval`](https://github.com/jitsi/jitsi-videobridge/blob/master/jvb/src/main/resources/reference.conf#L65) property.
|
||||
|
||||
|
||||
# Supported metrics
|
||||
Below is a non-exhaustive list of currently supported metrics. In the descriptions "current" means an instantaneous
|
||||
value (when the report was generated), and "total" means a cumulative value since the application was started.
|
||||
|
||||
* `bit_rate_download` - the current incoming bitrate (RTP) in kilobits per second.
|
||||
* `bit_rate_upload` - the current outgoing bitrate (RTP) in kilobits per second.
|
||||
* `conferences` - The current number of conferences.
|
||||
* `current_timestamp` - the UTC time at which the report was generated.
|
||||
* `dtls_failed_endpoints` - the total number of endpoints which failed to establish a DTLS connection.
|
||||
* `endpoints` - the current number of endpoints, including `octo` endpoints.
|
||||
* `endpoints_sending_audio` - current number of endpoints sending (non-silence) audio.
|
||||
* `endpoints_sending_video` - current number of endpoints sending video.
|
||||
* `endpoints_with_spurious_remb` - total number of endpoints which have sent an RTCP REMB packet when REMB was not
|
||||
signaled.
|
||||
* `graceful_shutdown` - whether jitsi-videobridge is currently in graceful shutdown mode (hosting existing conferences,
|
||||
but not accepting new ones).
|
||||
* `inactive_conferences` - current number of conferences in which no endpoints are sending audio nor video. Note that
|
||||
this includes conferences which are currently using a peer-to-peer transport.
|
||||
* `inactive_endpoints` - current number of endpoints in inactive conferences (see `inactive_conferences`).
|
||||
* `largest_conference` - the size of the current largest conference (counting all endpoints, including `octo`
|
||||
endpoints which are connected to a different jitsi-videobridge instance)
|
||||
* `local_active_endpoints` - the current number of local endpoints (not `octo`) which are in an active conference. This
|
||||
includes endpoints which are not sending audio or video, but are in an active conference (i.e. they are receive-only).
|
||||
* `local_endpoints` - the current number of local (non-`octo`) endpoints.
|
||||
* `num_eps_oversending` - current number of endpoints to which we are oversending.
|
||||
* `octo_conferences` - current number of conferences in which `octo` is enabled.
|
||||
* `octo_endpoints` - current number of `octo` endpoints (connected to remove jitsi-videobridge instances).
|
||||
* `octo_receive_bitrate` - current incoming bitrate on the `octo` channel (combined for all conferences) in bits per
|
||||
second.
|
||||
* `octo_receive_packet_rate` - current incoming packet rate on the `octo` channel (combined for all conferences) in
|
||||
packets per second.
|
||||
* `octo_send_bitrate` - current outgoing bitrate on the `octo` channel (combined for all conferences) in bits per
|
||||
second.
|
||||
* `octo_send_packet_rate` - current outgoing packet rate on the `octo` channel (combined for all conferences) in
|
||||
packets per second.
|
||||
* `p2p_conferences` - current number of peer-to-peer conferences. These are conferences of size 2 in which no endpoint
|
||||
is sending audio not video. Presumably the endpoints are using a peer-to-peer transport at this time.
|
||||
* `packet_rate_download` - current RTP incoming packet rate in packets per second.
|
||||
* `packet_rate_upload` - current RTP outgoing packet rate in packets per second.
|
||||
* `participants` - current number of endpoints, including `octo` endpoints. Deprecated.
|
||||
* `preemptive_kfr_sent` - total number of preemptive keyframe requests sent.
|
||||
* `receive_only_endpoints` - current number of endpoints which are not sending audio nor video.
|
||||
* `region` - preconfigured region used for bridge selection in jicofo.
|
||||
* `relay_id` - encodes the `octo` address of this bridge.
|
||||
* `rtt_aggregate` - round-trip-time measured via RTCP averaged over all local endpoints with a valid RTT measurement in
|
||||
milliseconds.
|
||||
* `stress_level` - current stress level on the bridge, with 0 indicating no load and 1 indicating the load is at full
|
||||
capacity (though values >1 are permitted).
|
||||
* `threads` - current number of JVM threads.
|
||||
* `total_bytes_received` - total number of bytes received in RTP.
|
||||
* `total_bytes_received_octo` - total number of bytes received on the `octo` channel.
|
||||
* `total_bytes_sent` - total number of bytes sent in RTP.
|
||||
* `total_bytes_sent_octo` - total number of bytes sent on the `octo` channel.
|
||||
* `total_colibri_web_socket_messages_received` - total number of messages received on a Colibri "bridge channel"
|
||||
messages received on a WebSocket.
|
||||
* `total_colibri_web_socket_messages_sent` - total number of messages sent over a Colibri "bridge channel" messages
|
||||
sent over a WebSocket.
|
||||
* `total_conference_seconds` - total number of conference-seconds served (only updates once a conference expires).
|
||||
* `total_conferences_completed` - total number of conferences completed.
|
||||
* `total_conferences_created` - total number of conferences created.
|
||||
* `total_data_channel_messages_received` - total number of Colibri "bridge channel" messages received on SCTP data
|
||||
channels.
|
||||
* `total_data_channel_messages_sent` - total number of Colibri "bridge channel" messages sent over SCTP data
|
||||
channels.
|
||||
* `total_dominant_speaker_changes` - total number of times the dominant speaker in a conference changed.
|
||||
* `total_failed_conferences` - total number of conferences in which no endpoints succeeded to establish an ICE
|
||||
connection.
|
||||
* `total_ice_failed` - total number of endpoints which failed to establish an ICE connection.
|
||||
* `total_ice_succeeded` - total number of endpoints which successfully established an ICE connection.
|
||||
* `total_ice_succeeded_relayed` - total number of endpoints which connected through a TURN relay (currently broken).
|
||||
* `total_packets_dropped_octo` - total number of packets dropped on the `octo` channel.
|
||||
* `total_packets_received` - total number of RTP packets received.
|
||||
* `total_packets_received_octo` - total number packets received on the `octo` channel.
|
||||
* `total_packets_sent` - total number of RTP packets sent.
|
||||
* `total_packets_sent_octo` - total number packets sent over the `octo` channel.
|
||||
* `total_partially_failed_conferences` - total number of conferences in which at least one endpoint failed to establish
|
||||
an ICE connection.
|
||||
* `total_participants` - total number of endpoints created.
|
||||
* `version` - the version of jitsi-videobridge.
|
||||
* `videochannels` - current number of endpoints with a video channel (i.e. which support receiving video). Deprecated.
|
||||
124
doc/svc.md
Normal file
124
doc/svc.md
Normal file
@@ -0,0 +1,124 @@
|
||||
# SSRC rewriting principles for VP8 simulcast/SVC
|
||||
|
||||
WebRTC has no notion of [simulcast][simulcast] when receiving a video stream,
|
||||
and it is therefore critical that any switch made by the SFU must be completely
|
||||
transparent to the receiver [1].
|
||||
|
||||
1) In the case of sending an RTP stream without using picture ids the SFU has
|
||||
to rewrite the RTP sequence numbers so that the stream looks continuous, and
|
||||
rewrite the RTP timestamps so that there is no significant jump compared to the
|
||||
last frame. The timestamp may not jump backward.
|
||||
|
||||
2) If picture ids are used, besides following the steps outlined in 1), the SFU
|
||||
also has to rewrite the picture ids to make them continuous. Note that it is
|
||||
not possible to suddenly drop picture ids from the stream, as the receiver only
|
||||
keeps state relevant to picture ids, if they are used and therefore won't fall
|
||||
back to RTP sequence numbers.
|
||||
|
||||
3) If picture ids, tl0 picture indexes and temporal indexes are used, besides
|
||||
following the steps outlined in 2), the SFU also has to rewrite the tl0 picture
|
||||
indexes. Note that it is possible to drop the tl0 picture indexes and the
|
||||
temporal indexes from the stream, but if they are used again the tl0 picture
|
||||
index has to continue from where it left off. Also note that the state of the
|
||||
tl0 picture indexes is only updated by the receiver when both the tl0 picture
|
||||
index and temporal index is received.
|
||||
|
||||
# Analysis
|
||||
|
||||
With simple simulcast, the SFU simply needs to apply a fixed delta (i.e. linear
|
||||
translation) to the RTP sequence numbers/timestamps [4] and VP8
|
||||
picture IDs/tl0picidx [3] that it forwards. The specific deltas are determined
|
||||
when the stream switching occurs. This straightforward approach doesn't work
|
||||
well if the SFU wants to leverage VP8 temporal scalability. We start our
|
||||
analysis by exploring the implications of the first guideline and, as we will
|
||||
see, 2 and 3 follow naturally.
|
||||
|
||||
With temporal scalability in VP8 (and other codecs)[2], where the SFU can drop frames to achieve
|
||||
lower frame rates, applying a fixed delta would leave gaps in the sequence
|
||||
numbers (because of the packets that the SFU drops). So the SFU needs to keep
|
||||
track of what it's sent and manage the sequence number space of the
|
||||
SFU-receiver leg (i.e. generate sequence numbers for every egress packet of a
|
||||
frame). This mode of operation has several implications.
|
||||
|
||||
First, it means that if the SFU decides to skip a frame for whatever reason,
|
||||
it cannot go back and change that decision because there would be no space left
|
||||
in the sequence numbers. Furthermore, if packet re-ordering or loss has occurred,
|
||||
a decision must be made immediately as to how much of a gap to leave in the
|
||||
sequence numbers so delayed packets have a place to be transmitted.
|
||||
|
||||
When a frame arrives and it is to be forwarded, the SFU needs to determine how to
|
||||
assign its projected sequence numbers. Decisions on how to assign sequence numbers
|
||||
are done by comparing the _new_ frame with an _existing_ (previously-projected) frame.
|
||||
(In most cases this existing frame will be the previous projected frame, in sequence number
|
||||
ordering to the new frame, though in some corner cases involving very old frames
|
||||
a different existing frame is chosen.)
|
||||
|
||||
If there is a gap in receive sequence numbers between the existing and the new frame,
|
||||
the SFU can determine the worst-case gap size of projected sequence numbers to
|
||||
leave such that any not-yet-received packets can be forwarded correctly.
|
||||
However, the SFU can't (in general) know the temporal layer of frames it has
|
||||
not yet received. If it turns out that the not-yet-received frames were in fact
|
||||
not ones that the SFU wanted to forward, this will result in sequence number
|
||||
gaps in the projected packet sequence, which the receiver may interpret as packet
|
||||
loss. (Care must be taken in bandwidth estimation algorithms not to incorrectly
|
||||
reduce bandwidth based on this "false" packet loss; in particular, this means
|
||||
that senders operating on receiver-side REMB-based bandwidth estimation mustn't
|
||||
adjust the estimates based on received loss.)
|
||||
|
||||
# Examples of projection
|
||||
|
||||
## Scenario A: Happy path (target TL0)
|
||||
|
||||
Sender sends: TL0 (1, 2, 3), TL2 (4, 5), TL1 (6, 7), TL2 (8), TL0 (9, 10, 11)
|
||||
|
||||
Bridge receives: what the sender sends
|
||||
|
||||
Bridge sends: 101, 102, 103, (9 -> 104), (10 -> 105), (11 -> 106)
|
||||
|
||||
When packet 9 arrives, the bridge can determine that sequence numbers 4 - 8
|
||||
belong to non-routed packets and can be suppressed
|
||||
|
||||
## Scenario B: packet loss (target TL2)
|
||||
|
||||
Sender sends: TL0 (1, 2, 3), TL2 (4, 5), TL1 (6, 7), TL2 (8), TL0 (9, 10, 11)
|
||||
|
||||
Bridge receives: 1, 2, 3, 4, _(X)_, 6, 7, 8, 9, 10, 11, 5
|
||||
|
||||
Bridge sends: 101, 102, 103, 104, 106, 107, 108, 109, 110, 111, 105
|
||||
|
||||
When packet 6 arrives, the bridge computes the gap from the previously projected
|
||||
frame. Because it wants to route both the TL2 and TL1 frames, it leaves
|
||||
a gap in the outgoing sequence numbers, into which packet 5 can later be slotted.
|
||||
|
||||
## Scenario C: packet loss 1 (target TL0)
|
||||
|
||||
Sender sends: TL0 (1, 2, 3), TL2 (4, 5), TL1 (6, 7), TL2 (8), TL0 (9, 10, 11)
|
||||
|
||||
Bridge receives: 1, 2, 3, 4, _(X)_, 6, 7, 8, 9, 10, 11, 5
|
||||
|
||||
Bridge sends: 101, 102, 103, (9 -> 104), (10 -> 105), (11 -> 106)
|
||||
|
||||
Similarly to Scenario A, when packet 9 arrives, the bridge can determine that
|
||||
sequence numbers 4-8 belong to non-routed packets. The status of the
|
||||
unreceived packet 5 can be determined because packet 4 will not have its
|
||||
"end of frame" flag set.
|
||||
|
||||
## Scenario D: packet loss 2 (target TL1)
|
||||
|
||||
Sender sends: TL0 (1, 2, 3), TL2 (4, 5), TL1 (6, 7), TL2 (8), TL0 (9, 10, 11)
|
||||
|
||||
Bridge receives: 1, 2, 3, 4, 5, 6, 7, _(X)_, 9, 10, 11, 8
|
||||
|
||||
Bridge sends: 101, 102, 103, (6 -> 104), (7 -> 105), (9 -> 107), (10 -> 108), (11 -> 109)
|
||||
|
||||
In this case, when packet 9 arrives, the bridge cannot determine what type of
|
||||
frame packet 8 was -- it could have been a TL1. Therefore it must leave a gap in
|
||||
the outgoing sequence numbers.
|
||||
|
||||
|
||||
[simulcast]: https://ieeexplore.ieee.org/abstract/document/7992929
|
||||
[1]: https://groups.google.com/d/topic/discuss-webrtc/gik2VH4hUjk/discussion
|
||||
[2]: https://webrtchacks.com/sfu-simulcast/
|
||||
[3]: https://tools.ietf.org/html/rfc7741
|
||||
[4]: https://tools.ietf.org/html/rfc3550
|
||||
|
||||
130
doc/web-sockets.md
Normal file
130
doc/web-sockets.md
Normal file
@@ -0,0 +1,130 @@
|
||||
# Introduction
|
||||
WebSockets can be used instead of WebRTC Data Channels for transport of Colibri
|
||||
client-to-bridge messages. This needs support from the bridge as well as the
|
||||
client.
|
||||
|
||||
When this is enabled, a bridge will advertise a Colibri WebSocket URL together with
|
||||
its ICE candidates. The URL will be specific to an endpoint (in fact the ICE username
|
||||
fragment is reused, encoded as a URL parameter, for authentication), and connections
|
||||
to it will be routed to the Endpoint representation in the bridge.
|
||||
|
||||
The URL has the following format:
|
||||
```
|
||||
wss://example.com/colibri-ws/server-id/conf-id/endpoint-id?pwd=123
|
||||
```
|
||||
|
||||
For secure-octo relays the URL has the following format:
|
||||
```
|
||||
wss://example.com/colibri-relay-ws/server-id/conf-id/relay-id?pwd=123
|
||||
```
|
||||
|
||||
# Bridge configuration
|
||||
To enable WebSockets on the bridge, both the publicly-accessible HTTP server and WebSockets
|
||||
themselves must be enabled.
|
||||
|
||||
The following block in jvb.conf configures the publicly-accessible HTTP server:
|
||||
|
||||
To enable the publicly-accessible HTTP server without TLS:
|
||||
```
|
||||
videobridge {
|
||||
http-servers {
|
||||
public {
|
||||
port = 9090
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To enable the publicly-accessible HTTP server with TLS:
|
||||
```
|
||||
videobridge {
|
||||
http-servers {
|
||||
public {
|
||||
tls-port = 443
|
||||
key-store-path=/etc/jitsi/videobridge/ssl.store
|
||||
key-store-password=KEY_STORE_PASSWORD
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To enable WebSockets:
|
||||
```
|
||||
videobridge {
|
||||
websockets {
|
||||
enabled = true
|
||||
tls = true # or false, depending on your HTTP server config
|
||||
# The port here is the 'advertise port' for websockets, which means the publicly-accessible
|
||||
# port clients will use. This may match the public http server port, but could also be different
|
||||
# if a proxy is being used.
|
||||
domain = "example.com:443"
|
||||
# A server ID can optionally be provided. This is useful when a set of jitsi-videobridge instances
|
||||
# are fronted by an HTTP proxy and they advertise the same domain.
|
||||
server-id = jvb2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Proxy configuration
|
||||
If you are using an HTTP proxy, it needs to support WebSocket. The following is
|
||||
an example `nginx` configuration which fronts two bridges. The two bridges use
|
||||
ports `9090` and `9091` without TLS, and are configured with
|
||||
`COLIBRI_WS_SERVER_ID=jvb1` and `jvb2` (see above) respectively.
|
||||
|
||||
```
|
||||
# colibri (JVB) websockets for jvb1
|
||||
location ~ ^/colibri-ws/jvb1/(.*) {
|
||||
proxy_pass http://127.0.0.1:9090/colibri-ws/jvb1/$1$is_args$args;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
tcp_nodelay on;
|
||||
}
|
||||
location ~ ^/colibri-ws/jvb2/(.*) {
|
||||
proxy_pass http://127.0.0.1:9091/colibri-ws/jvb2/$1$is_args$args;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host alpha.jitsi.net;
|
||||
tcp_nodelay on;
|
||||
}
|
||||
```
|
||||
|
||||
This configuration allows two jitsi-videobridge instances to run on the same
|
||||
machine, which is useful while testing Octo.
|
||||
|
||||
For secure-octo the `/colibri-relay-ws` endpoints also need to be proxied:
|
||||
```
|
||||
# colibri secure-octo relay websockets for jvb1
|
||||
location ~ ^/colibri-relay-ws/jvb1/(.*) {
|
||||
proxy_pass http://127.0.0.1:9090/colibri-relay-ws/jvb1/$1$is_args$args;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
tcp_nodelay on;
|
||||
}
|
||||
location ~ ^/colibri-relay-ws/jvb2/(.*) {
|
||||
proxy_pass http://127.0.0.1:9091/colibri-relay-ws/jvb2/$1$is_args$args;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host alpha.jitsi.net;
|
||||
tcp_nodelay on;
|
||||
}
|
||||
```
|
||||
|
||||
# Troubleshooting
|
||||
To verify that WebSockets are configured and used, first check that the Colibri
|
||||
WebSocket URL is advertised to the clients. Open a conference and look for
|
||||
"session-initiate" in the javascript console logs. Extend the XML and look for
|
||||
`description -> content -> transport`. You should see a `web-socket` element
|
||||
like this (you can verify this on meet.jit.si):
|
||||
|
||||
```xml
|
||||
<web-socket xmlns="http://jitsi.org/protocol/colibri" url="wss://meet-jit-si-eu-west-2b-s5-jvb-51.jitsi.net:443/colibri-ws/default-id/4f9cb343985d4779/c814b6a6?pwd=23btmrjol5i83thk1t9s78bnkk"/>
|
||||
```
|
||||
|
||||
Make sure that the URL is correct, and that your infrastructure routes it to
|
||||
the correct jitsi-videobridge instance. Finally, check the `Network` tab in the
|
||||
Chrome dev console and look for requests to this URL. You should see a websocket
|
||||
opened to this URL, and messages exchanged every few seconds.
|
||||
Reference in New Issue
Block a user