Checkpoint audio-only Skald fork work

This commit is contained in:
Storm Dragon
2026-05-18 13:06:57 -04:00
parent a8ada950d5
commit 965347cad4
48 changed files with 1080 additions and 3651 deletions
+39 -47
View File
@@ -2,9 +2,9 @@
## Data structures
### Group
### Hall
A group is a set of clients. It is identified by a human-readable name
A hall is a set of clients. It is identified by a human-readable name
that must not start or end with a slash "`/`", must not start with
a period "`.`", and must not contain the substrings "`/../`" or "`/./`".
@@ -28,24 +28,24 @@ server to client direction.
## Before connecting
The client needs to know the location of the group, the (user-visible) URL
at which the group is found. This may be obtained either by explicit
The client needs to know the location of the hall, the (user-visible) URL
at which the hall is found. This may be obtained either by explicit
configuration by the user, or by parsing the `/public-halls.json` file
which may contain an array of group statuses (see below).
which may contain an array of hall statuses (see below).
A client then performs an HTTP GET request on the file `.status` at
the group's location. This yields a single JSON object, which contains
the hall's location. This yields a single JSON object, which contains
the following fields:
- `name`: the group's name
- `location`: the group's location
- `name`: the hall's name
- `location`: the hall's location
- `endpoint`: the URL of the server's WebSocket endpoint
- `displayName`: a longer version of the name used for display;
- `description`: a user-readable description;
- `authServer`: the URL of the authentication server, if any;
- `authPortal`: the uRL of the authentication portal, if any;
- `locked`: true if the group is locked;
- `clientCount`: the number of clients currently in the group.
- `locked`: true if the hall is locked;
- `clientCount`: the number of clients currently in the hall.
All fields are optional except `name`, `location` and `endpoint`.
@@ -119,13 +119,13 @@ The receiving peer must reply with a `pong` message within 30s.
## Joining and leaving
The `join` message requests that the sender join or leave a group:
The `join` message requests that the sender join or leave a hall:
```javascript
{
type: 'join',
kind: 'join' or 'leave',
group: group,
hall: hall,
username: username,
password: password,
data: data
@@ -135,7 +135,7 @@ The `join` message requests that the sender join or leave a group:
If token-based authorisation is beling used, then the `username` and
`password` fields are omitted, and a `token` field is included instead.
When the sender has effectively joined the group, the peer will send
When the sender has effectively joined the hall, the peer will send
a 'joined' message of kind 'join'; it may then send a 'joined' message of
kind 'change' at any time, in order to inform the client of a change in
its permissions or in the recommended RTC configuration.
@@ -145,7 +145,7 @@ its permissions or in the recommended RTC configuration.
type: 'joined',
kind: 'join' or 'fail' or 'change' or 'leave',
error: may be set if kind is 'fail',
group: group,
hall: hall,
username: username,
permissions: permissions,
status: status,
@@ -157,12 +157,12 @@ its permissions or in the recommended RTC configuration.
The `username` field is the username that the server assigned to this
user. The `permissions` field is an array of strings that may contain the
values `present`, `op` and `record`. The `status` field is a dictionary
that contains status information about the group, and updates the data
that contains status information about the hall, and updates the data
obtained from the `.status` URL described above.
## Maintaining group membership
## Maintaining hall membership
Whenever a user joins or leaves a group, the server will send all other
Whenever a user joins or leaves a hall, the server will send all other
users a `user` message:
```javascript
@@ -188,15 +188,14 @@ A peer must explicitly request the streams that it wants to receive.
```
The field `request` is a dictionary that maps the labels of requested
streams to a list containing either 'audio', or one of 'video' or
'video-low'. The empty key `''` serves as default. For example:
streams to a list containing `audio`. The empty key `''` serves as
default. For example:
```javascript
{
type: 'request',
request: {
camera: ['audio', 'video-low'],
'': ['audio', 'video']
'': ['audio']
}
}
```
@@ -220,23 +219,16 @@ A stream is created by the sender with the `offer` message:
If a stream with the same id exists, then this is a renegotiation;
otherwise this message creates a new stream. If the field `replace` is
not empty, then this request additionally requests that an existing stream
with the given id should be closed, and the new stream should replace it;
this is used most notably when changing the simulcast envelope.
with the given id should be closed, and the new stream should replace it.
The field `label` is one of `camera`, `screenshare` or `video`, and will
be matched against the keys sent by the receiver in their `request` message.
The field `label` is normally `audio`, and will be matched against the
keys sent by the receiver in their `request` message.
The field `sdp` contains the raw SDP string (i.e. the `sdp` field of
a JSEP session description). Skald will interpret the `nack`,
`nack pli`, `ccm fir` and `goog-remb` RTCP feedback types, and act
accordingly.
a JSEP session description). Skald is audio-only; video media sections
are not accepted.
The sender may either send a single stream per media section in the SDP,
or use rid-based simulcasting with the streams ordered in decreasing order
of throughput. In that case, it should send two video streams, the
first one with high throughput, and the second one with throughput limited
to roughly 100kbit/s. If more than two streams are sent, then only the
first and the last one will be considered.
The sender sends a single audio stream per media section in the SDP.
The receiver may either abort the stream immediately (see below), or send
an answer.
@@ -275,7 +267,7 @@ being offered by sending a 'requestStream' request:
{
type: 'requestStream'
id: id,
request: [audio, video]
request: [audio]
}
```
@@ -329,7 +321,7 @@ The field `kind` can have one of the following values:
the `caption` permission).
If `dest` is empty, the message is a broadcast message, destined to all of
the clients in the group. If `source` is empty, then the message was
the clients in the hall. If `source` is empty, then the message was
originated by the server. The message is forwarded by the server without
interpretation, the server only validates that the `source` and `username`
fields are authentic. The field `privileged` is set to true by the server
@@ -359,7 +351,7 @@ chat history, and is not expected to contain user-visible content.
```
Currently defined kinds include `error`, `warning`, `info`, `kicked`,
`clearchat` (not to be confused with the `clearchat` group action), and
`clearchat` (not to be confused with the `clearchat` hall action), and
`mute`.
A user action requests that the server act upon a user.
@@ -377,11 +369,11 @@ A user action requests that the server act upon a user.
Currently defined kinds include `op`, `unop`, `present`, `unpresent`,
`kick` and `setdata`.
Finally, a group action requests that the server act on the current group.
Finally, a hall action requests that the server act on the current hall.
```javascript
{
type: 'groupaction',
type: 'hallaction',
kind: kind,
source: source-id,
username: username,
@@ -391,7 +383,7 @@ Finally, a group action requests that the server act on the current group.
Currently defined kinds include `clearchat` (not to be confused with the
`clearchat` user message), `lock`, `unlock`, `record`, `unrecord`,
`subgroups` and `setdata`.
`subhalls` and `setdata`.
# Peer-to-peer file transfer protocol
@@ -552,8 +544,8 @@ Javascript code.
## Authentication server
If a group's status dictionary has a non-empty `authServer` field, then
the group uses an authentication server. Before joining, the client sends
If a hall's status dictionary has a non-empty `authServer` field, then
the hall uses an authentication server. Before joining, the client sends
a POST request to the authorisation server URL containing in its body
a JSON dictionary of the following form:
```javascript
@@ -564,7 +556,7 @@ a JSON dictionary of the following form:
}
```
If the user is not allowed to join the group, then the authorisation
If the user is not allowed to join the hall, then the authorisation
server replies with a code of 403 ("not authorised"), and Skald will
reject the user. If the authentication server has no opinion about
whether the user is allowed to join, it replies with a code of 204 ("no
@@ -587,16 +579,16 @@ the same format as in the `joined` message. Since the client will only
use the token once, at the very beginning of the session, the tokens
issued may have a short lifetime (on the order of 30s).
A boolean `include-subgroups` claim may be included in the JWT payload. It
has the same effect as the `include-subgroups` parameter used when generating
A boolean `include-subhalls` claim may be included in the JWT payload. It
has the same effect as the `include-subhalls` parameter used when generating
a stateful token.
## Authentication portal
If a group's status dictionary has a non-empty `authPortal` field, Skald
If a hall's status dictionary has a non-empty `authPortal` field, Skald
redirects the user agent to the URL indicated by `authPortal`. The
authentication portal performs authorisation, generates a token as above,
then redirects back to the group's URL with the token stores in a URL
then redirects back to the hall's URL with the token stores in a URL
query parameter named `token`:
https://skald.example.org/hall/hallname/?token=eyJhbG...