@voltkit-rtc/client 0.6.1 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +109 -2
- package/README.md +236 -11
- package/dist/cjs/broadcast.d.ts.map +1 -1
- package/dist/cjs/broadcast.js +16 -7
- package/dist/cjs/broadcast.js.map +1 -1
- package/dist/cjs/chat.d.ts +11 -9
- package/dist/cjs/chat.d.ts.map +1 -1
- package/dist/cjs/chat.js +56 -19
- package/dist/cjs/chat.js.map +1 -1
- package/dist/cjs/errors.d.ts +571 -0
- package/dist/cjs/errors.d.ts.map +1 -0
- package/dist/cjs/errors.js +155 -0
- package/dist/cjs/errors.js.map +1 -0
- package/dist/cjs/index.d.ts +320 -16
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +728 -123
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/media-permissions.d.ts +101 -0
- package/dist/cjs/media-permissions.d.ts.map +1 -0
- package/dist/cjs/media-permissions.js +166 -0
- package/dist/cjs/media-permissions.js.map +1 -0
- package/dist/cjs/network.d.ts +80 -0
- package/dist/cjs/network.d.ts.map +1 -0
- package/dist/cjs/network.js +190 -0
- package/dist/cjs/network.js.map +1 -0
- package/dist/cjs/token.d.ts +17 -0
- package/dist/cjs/token.d.ts.map +1 -0
- package/dist/cjs/token.js +36 -0
- package/dist/cjs/token.js.map +1 -0
- package/dist/esm/broadcast.d.ts.map +1 -1
- package/dist/esm/broadcast.js +16 -7
- package/dist/esm/broadcast.js.map +1 -1
- package/dist/esm/chat.d.ts +11 -9
- package/dist/esm/chat.d.ts.map +1 -1
- package/dist/esm/chat.js +56 -19
- package/dist/esm/chat.js.map +1 -1
- package/dist/esm/errors.d.ts +571 -0
- package/dist/esm/errors.d.ts.map +1 -0
- package/dist/esm/errors.js +149 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/index.d.ts +320 -16
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +707 -114
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/media-permissions.d.ts +101 -0
- package/dist/esm/media-permissions.d.ts.map +1 -0
- package/dist/esm/media-permissions.js +160 -0
- package/dist/esm/media-permissions.js.map +1 -0
- package/dist/esm/network.d.ts +80 -0
- package/dist/esm/network.d.ts.map +1 -0
- package/dist/esm/network.js +183 -0
- package/dist/esm/network.js.map +1 -0
- package/dist/esm/token.d.ts +17 -0
- package/dist/esm/token.d.ts.map +1 -0
- package/dist/esm/token.js +31 -0
- package/dist/esm/token.js.map +1 -0
- package/package.json +1 -1
- package/src/broadcast.ts +16 -7
- package/src/chat.ts +44 -18
- package/src/errors.ts +162 -0
- package/src/index.ts +842 -114
- package/src/media-permissions.ts +220 -0
- package/src/network.ts +212 -0
- package/src/token.ts +31 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,113 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 0.7.1
|
|
4
|
+
|
|
5
|
+
Bug fixes. No API changes; nothing to change in your code. An external review
|
|
6
|
+
(2026-10-16) found lifecycle bugs in the Flutter SDK and transport bugs in the
|
|
7
|
+
Node SDK. This release fixes the same kinds of bug, found in this SDK by the
|
|
8
|
+
check that followed.
|
|
9
|
+
|
|
10
|
+
- **BROWSER-01: `close()` is final while a connection is being made.**
|
|
11
|
+
- Before, closing while `connect()` waited for the join left `connect()`
|
|
12
|
+
pending for about 15 s, after which it failed with `timeout`.
|
|
13
|
+
- Closing just after the join, while the session was still being set up, put
|
|
14
|
+
`connectionState` back to `connected` and emitted `joined` after `closed`.
|
|
15
|
+
- Closing during a reconnect could emit an `error` after `closed`.
|
|
16
|
+
|
|
17
|
+
Now `close()` fails `connect()` and every request in flight at once, with
|
|
18
|
+
`not-connected`, and nothing is emitted after `closed`. The same holds for
|
|
19
|
+
`ChatClient`. `ChatClient.close()` now also closes a socket opened by a
|
|
20
|
+
`connect()` after an earlier `close()`, which it could not reach before.
|
|
21
|
+
- **BROWSER-02: a reconnect that ends the session closes its socket.** When
|
|
22
|
+
the server refused a reconnect for good (`room-ended`, `bad-token`, …), or the
|
|
23
|
+
reconnect attempts ran out, the session reported `closed: gave-up` but kept
|
|
24
|
+
the refused socket open and attached. Now that socket is closed and later
|
|
25
|
+
requests are refused without being sent. Both `StreamClient` and `ChatClient`.
|
|
26
|
+
- **BROWSER-03: `endRoom()` resolves when the room closes first.** The server
|
|
27
|
+
tells the room it has closed before it replies to `endRoom`, and that closes
|
|
28
|
+
the session, so the reply was never read and `endRoom()` failed with `timeout`
|
|
29
|
+
15 s later, although the room had ended. Now a `roomClosed` that arrives
|
|
30
|
+
first resolves `endRoom()` with `{ ok: true }`, as the reply would. A refusal,
|
|
31
|
+
or a dropped connection with neither, still fails.
|
|
32
|
+
- **BROWSER-04: WHIP failures while reading the answer are `WhipError`s.**
|
|
33
|
+
`BroadcastPublisher.start()` failed with a raw `TimeoutError` or `TypeError`
|
|
34
|
+
when the media server's answer timed out or the connection dropped after its
|
|
35
|
+
headers. Now they are `WhipError`s with `status` 0, like the same failures
|
|
36
|
+
before the headers. The publish URL is never in the message.
|
|
37
|
+
- **BROWSER-05: a `null` message frame is ignored.** Valid JSON that is not a
|
|
38
|
+
message object no longer throws out of the socket's message listener; other
|
|
39
|
+
frames that are not messages were already ignored.
|
|
40
|
+
- Docs: the README says 60 fps is delivered only when the capture source
|
|
41
|
+
provides it (most phone and laptop cameras give browsers 30 fps), how to check
|
|
42
|
+
a camera's rates, and that billing follows the frame rate delivered.
|
|
43
|
+
|
|
44
|
+
## 0.7.0
|
|
45
|
+
|
|
46
|
+
Additive: every 0.6 call works as before. Pairs with the controller's wallet
|
|
47
|
+
billing (join result `media` and `billing`, `walletLow`, `refreshToken`) and
|
|
48
|
+
works with older controllers too.
|
|
49
|
+
|
|
50
|
+
- **Audio quality.** `PublishOptions.audioQuality: 'std' | 'hd'`, `setAudioQuality()`
|
|
51
|
+
live and the `audioQuality` getter. Standard (the default) is mono Opus with
|
|
52
|
+
`maxaveragebitrate` 64000 and the sender held at 60 kbps (a little under the
|
|
53
|
+
declared rate: Opus VBR measured 60-65 kbps per 5 s window with a 64 kbps
|
|
54
|
+
cap, and standard must never measure above 64), so it stays standard on a
|
|
55
|
+
server that bills what it measures; HD is stereo Opus at up to 128 kbps.
|
|
56
|
+
`AUDIO_SETTINGS` carries both numbers (`maxBitrate`, `senderMaxBitrate`). The microphone's producer declares its `maxaveragebitrate` and
|
|
57
|
+
`appData.audioQuality` to the server. Switching re-creates the microphone's
|
|
58
|
+
producer and keeps it muted if it was. Music is unchanged (128 kbps stereo).
|
|
59
|
+
The microphone was stereo-flagged with no cap in 0.6.
|
|
60
|
+
- **Music is HD and free.** `publishMusic` stays a 128 kbps stereo track in
|
|
61
|
+
every project, also one limited to standard audio (the server allows it there
|
|
62
|
+
and never bills music: the microphone and video alone decide the tier).
|
|
63
|
+
- **Project media settings.** `mediaPermissions` (from the join result's
|
|
64
|
+
`media`, else the `video` policy) and `billingMode`. A kind the project
|
|
65
|
+
switched off is refused before anything is produced (`media-disabled`);
|
|
66
|
+
`setAudioQuality('hd')` without HD is refused (`audio-quality-not-allowed`);
|
|
67
|
+
HD in `publish()`, 60 fps without 60 fps modes and a 60 fps size that is not
|
|
68
|
+
enabled are capped with a warning carrying the server's code. Media profiles
|
|
69
|
+
narrow wallet sessions only. A wallet session waits for a video slot at
|
|
70
|
+
`media.fanout.maxVideoSubscriptions` instead of asking for a refusal.
|
|
71
|
+
- **Changed:** 60 fps refused by the project now warns `frame-rate-not-allowed`
|
|
72
|
+
(the server's code); `frame-rate-fallback` now means only that the camera,
|
|
73
|
+
device or upload cannot provide 60. `setVideoFrameRate(60)` in such a project
|
|
74
|
+
no longer re-creates the camera's producer.
|
|
75
|
+
- **Network quality.** `networkQuality { level, rttMs, lossPct, availableKbps }`
|
|
76
|
+
about every 3 s while listened to, from the transports' statistics, with the
|
|
77
|
+
thresholds in the README.
|
|
78
|
+
- **Tokens.** `updateToken(token)` sends a newer token on the live connection
|
|
79
|
+
(`refreshToken`; older servers keep it for the next reconnect), and
|
|
80
|
+
`tokenExpiring { expiresAt, secondsLeft }` fires a minute before the held
|
|
81
|
+
token expires when nobody refreshed it. Server-pushed tokens carry `expiresAt`.
|
|
82
|
+
- **Wallet.** Typed `walletLow { remainingSeconds, cleared? }`.
|
|
83
|
+
- **Connection state.** `connectionState` and `connectionStateChanged`
|
|
84
|
+
(`idle`, `connecting`, `connected`, `reconnecting`, `closed`).
|
|
85
|
+
- **Parity with the wire:** `claim`, `release`, `blockSlot`, `unblockSlot`,
|
|
86
|
+
`setMetadata`, `setRoomMetadata` and the `claimChanged`, `participantUpdated`
|
|
87
|
+
and `roomMetadataChanged` events, as the Flutter, Android and Swift SDKs
|
|
88
|
+
have. `info` keeps the roster, slots and room metadata current;
|
|
89
|
+
`participants` and `remoteTracks` getters.
|
|
90
|
+
- **Errors.** One registry shared by every SDK (`ERROR_CODES`, `errorInfo`,
|
|
91
|
+
`isTerminalError`, `ErrorCode`); every error the SDK raises is an `RpcError`
|
|
92
|
+
with a registry code (`not-connected`, `timeout`, `connect-failed`,
|
|
93
|
+
`replaced`, `reconnect-gave-up`, `devices-gone`, `unpublished`,
|
|
94
|
+
`codec-fallback`, ...); `RpcError.data` carries what the server attached.
|
|
95
|
+
`kicked` and `billing-unavailable` now end a reconnect at once, like the other
|
|
96
|
+
terminal codes. `CLIENT_EVENTS` and `CONNECTION_STATES` list the names.
|
|
97
|
+
- **Constructor options** (added 2026-10-14, before 0.7.0's first publish):
|
|
98
|
+
`new StreamClient(wsUrl, token, options?)` with `ClientOptions.handlerName`
|
|
99
|
+
(`DeviceHandlerName`), the mediasoup-client handler to build the Device with
|
|
100
|
+
instead of detecting the browser. Reserved for future native hosts; unset,
|
|
101
|
+
nothing changes.
|
|
102
|
+
- **Socket URL** (same date): the `token` query parameter is appended by
|
|
103
|
+
string (`?token=` or `&token=` after an existing query, URL-encoded) instead
|
|
104
|
+
of through `URL.searchParams`, which some non-browser `URL` polyfills do not
|
|
105
|
+
implement. Identical URLs in browsers.
|
|
106
|
+
- No package is published by this change: the owner publishes.
|
|
107
|
+
|
|
108
|
+
## 0.6.1
|
|
109
|
+
|
|
110
|
+
(Published as RTC-REF-001.)
|
|
4
111
|
|
|
5
112
|
- Ignore hidden-page and in-flight pre-switch samples in `videoLimited` and the optional 60→30 fps fallback. Resume with warm-up and fresh counters; sustained foreground limitation still triggers fallback.
|
|
6
113
|
- FPS changes/fallback preserve existing capture constraints, including dimensions, facing mode and native-resize preference.
|
|
@@ -8,7 +115,7 @@
|
|
|
8
115
|
- Optional `VideoSendStats.source` (sender input dimensions/FPS), `encoderImplementation` and `powerEfficientEncoder` diagnostics. Unsupported browser fields remain absent; H264 alone does not establish hardware encoding.
|
|
9
116
|
- Codec selection, quality/bitrate ladders and publishing APIs are unchanged. Requires a new browser SDK publication and website dependency update to reach the deployed demo. No package published by this change.
|
|
10
117
|
|
|
11
|
-
## 0.6.0
|
|
118
|
+
## 0.6.0
|
|
12
119
|
|
|
13
120
|
- Paid camera recording: `StreamClient.startRecording` / `stopRecording`, `CameraRecording` and `RecordingUploader`. Admin-controlled capture resolution/bitrate/FPS, default 360p; independent live-call quality.
|
|
14
121
|
- Direct device-to-R2 multipart PUTs, 5/10 MiB chunks, bounded buffering, limited parallel uploads, retry URL renewal and recording-only backpressure. Short independently playable files; validation overlaps the next capture after upload buffers drain.
|
package/README.md
CHANGED
|
@@ -9,6 +9,9 @@ rooms, chat, and live broadcast publishing.
|
|
|
9
9
|
| **Chat** | on the room's own connection, or `ChatClient` for chat with no media |
|
|
10
10
|
| **Broadcast** | `BroadcastPublisher` — go live to an audience of any size over WHIP |
|
|
11
11
|
|
|
12
|
+
Using React or Next.js? [`@voltkit-rtc/react`](https://voltkit.in/docs/react-sdk)
|
|
13
|
+
wraps this client in a provider, hooks and track components.
|
|
14
|
+
|
|
12
15
|
Your backend mints a short-lived token with
|
|
13
16
|
[`@voltkit-rtc/server`](https://voltkit.in/docs/server-sdk) and
|
|
14
17
|
hands the page `{ token, wsUrl }`. This package turns that into a live session.
|
|
@@ -55,6 +58,13 @@ if (joined.role === 'host' || joined.role === 'cohost') {
|
|
|
55
58
|
Always call `client.close()` when leaving. A client that is dropped without
|
|
56
59
|
closing keeps its reconnect loop running.
|
|
57
60
|
|
|
61
|
+
`new StreamClient(wsUrl, token, options?)` takes `ClientOptions`, all optional
|
|
62
|
+
and none needed in a browser: `handlerName` names the mediasoup-client handler
|
|
63
|
+
to build the WebRTC side with (`'Chrome111'`, `'Chrome74'`, `'Firefox120'`,
|
|
64
|
+
`'Safari12'` or `'ReactNative106'`) instead of detecting the browser. It is
|
|
65
|
+
reserved for future native hosts, which have no browser to detect; leave it
|
|
66
|
+
unset.
|
|
67
|
+
|
|
58
68
|
### Publishing
|
|
59
69
|
|
|
60
70
|
```ts
|
|
@@ -74,6 +84,7 @@ phones and computers alike; they are kept for a reconnect's republish.
|
|
|
74
84
|
|
|
75
85
|
| Option | Default | What it does |
|
|
76
86
|
| --- | --- | --- |
|
|
87
|
+
| `audioQuality` | `'std'` | the microphone: `'std'` (mono, up to 64 kbps) or `'hd'` (stereo, up to 128 kbps); see [Audio quality](#audio-quality) |
|
|
77
88
|
| `quality` | the highest the project allows | `'1080p'`, `'720p'` or `'480p'`; see [Video quality](#video-quality) |
|
|
78
89
|
| `frameRate` | `30` | `30` or `60`; only the top layer runs at 60 fps; capture at 60 too |
|
|
79
90
|
| `layers` | `2` on phones and tablets, `3` elsewhere | the most simulcast layers to send. When a phone is too busy, the browser shrinks the picture and may then send fewer layers, dropping the top one: asked for two, it keeps the full picture; asked for three, viewers were left with a quarter of it |
|
|
@@ -112,8 +123,9 @@ const media = await navigator.mediaDevices.getUserMedia({ audio: true, video: {
|
|
|
112
123
|
await client.publish(media, undefined, { quality: '1080p' });
|
|
113
124
|
await client.setVideoQuality('480p'); // resolves to the quality actually used
|
|
114
125
|
|
|
115
|
-
client.videoPolicy;
|
|
116
|
-
client.videoQuality;
|
|
126
|
+
client.videoPolicy; // { maxQuality: '480p' | '720p' | '1080p', maxFrameRate, maxBitrate } for this project
|
|
127
|
+
client.videoQuality; // what is being sent now
|
|
128
|
+
client.videoFrameRate; // 30 or 60, what the camera is being sent at
|
|
117
129
|
```
|
|
118
130
|
|
|
119
131
|
| Quality | Layers from a computer at 30 fps | From a phone or tablet | Video upload |
|
|
@@ -140,14 +152,99 @@ const effectiveFps = await client.setVideoFrameRate(30); // camera only, other t
|
|
|
140
152
|
Only the top layer uses 60 fps: 1080p is **9 Mbps**, 720p **4.5 Mbps**, and
|
|
141
153
|
480p **1.8 Mbps**; smaller layers stay at 30. This means roughly 1.5× the top
|
|
142
154
|
layer's data and twice the encoding work. Phones can heat up and use more
|
|
143
|
-
battery, and many front cameras capture only 30.
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
`
|
|
155
|
+
battery, and many front cameras capture only 30. When 60 cannot be used the SDK
|
|
156
|
+
sends 30 and says why on `error`, as a warning that stops nothing:
|
|
157
|
+
|
|
158
|
+
| `code` | Why |
|
|
159
|
+
| --- | --- |
|
|
160
|
+
| `frame-rate-not-allowed` | the project does not allow 60 fps (its settings, or no 60 fps mode is enabled) |
|
|
161
|
+
| `video-quality-not-allowed` | 60 fps is allowed, but not at the size you asked for: the largest size that is goes out at 60 |
|
|
162
|
+
| `frame-rate-fallback` | the camera captures below 50 fps, or the device or upload cannot keep 60 up |
|
|
163
|
+
|
|
164
|
+
`setVideoFrameRate(60)` retries the preference while preserving a paused
|
|
165
|
+
camera; in a project without 60 fps it changes nothing and warns again.
|
|
166
|
+
(Before 0.7.0 the project case was also reported as `frame-rate-fallback`.)
|
|
167
|
+
|
|
168
|
+
60 fps is delivered only when the capture source provides it.
|
|
169
|
+
Phone makers usually keep 60 fps for their own camera app, so browsers and most
|
|
170
|
+
apps get 30 fps. Check a camera's supported rates in `chrome://media-internals`
|
|
171
|
+
→ Video Capture. Billing follows the frame rate actually delivered. In our
|
|
172
|
+
tests a laptop webcam gave Chrome 20 fps at 1080p, and a phone whose own camera
|
|
173
|
+
app records 1080p60 gave 25–30 fps (14 fps in a dim room). Read what you got,
|
|
174
|
+
not what you asked for: `track.getSettings().frameRate` is the rate the camera
|
|
175
|
+
was opened at, and `getVideoStats()` reports the rate captured (`source.fps`,
|
|
176
|
+
where the browser supplies it) and sent (`fps`). For 60 fps, use a webcam or
|
|
177
|
+
capture card listed at 60 fps, or a virtual camera such as OBS Virtual Camera
|
|
178
|
+
set to 60 fps.
|
|
147
179
|
|
|
148
180
|
The full guide, with data use:
|
|
149
181
|
[voltkit.in/docs/video-quality](https://voltkit.in/docs/video-quality).
|
|
150
182
|
|
|
183
|
+
### Audio quality
|
|
184
|
+
|
|
185
|
+
The microphone goes out as **standard** audio unless you ask for HD:
|
|
186
|
+
|
|
187
|
+
| `audioQuality` | Sent as | Billed as (wallet billing) |
|
|
188
|
+
| --- | --- | --- |
|
|
189
|
+
| `'std'` (default) | mono Opus, `maxaveragebitrate` 64000, the sender held at 60 kbps, DTX and FEC | standard audio |
|
|
190
|
+
| `'hd'` | stereo Opus, `maxaveragebitrate` 128000, DTX and FEC | HD audio |
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
await client.publish(media, undefined, { audioQuality: 'hd' });
|
|
194
|
+
await client.setAudioQuality('std'); // while live; resolves to the quality in use
|
|
195
|
+
client.audioQuality; // 'std' | 'hd'
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
The server bills what it can verify, never what a client claims: HD only when
|
|
199
|
+
the microphone declares more than 64 kbps or is measured above 72 kbps, so a
|
|
200
|
+
standard microphone really stays at or under 64 kbps: its sender is held at
|
|
201
|
+
60 kbps, a little under the declared rate, because Opus VBR around a 64 kbps
|
|
202
|
+
target measured up to 65 kbps in a 5 s window. Switching re-creates the
|
|
203
|
+
microphone's producer (its codec settings are fixed per producer): listeners
|
|
204
|
+
hear a gap of a fraction of a second, and a muted microphone stays muted.
|
|
205
|
+
|
|
206
|
+
For HD, capture with `{ audio: { channelCount: { ideal: 2 }, echoCancellation:
|
|
207
|
+
true, noiseSuppression: true, autoGainControl: true } }`; turn the processing
|
|
208
|
+
off only for headphones or line-in music, or listeners hear their own echo.
|
|
209
|
+
Music (`publishMusic`) is a separate 128 kbps stereo track and is not affected:
|
|
210
|
+
it is HD and free whatever the microphone's quality (see [Music](#music)).
|
|
211
|
+
|
|
212
|
+
### Project media settings
|
|
213
|
+
|
|
214
|
+
A project's owner chooses what it may publish: audio and video on or off, the
|
|
215
|
+
largest video quality, 30 or 60 fps, standard or HD audio. Allowing a mode
|
|
216
|
+
allows every mode below it (1080p at 60 fps opens 720p and 480p at 60 and every
|
|
217
|
+
30 fps mode). The join result carries them, and the client follows them:
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
client.mediaPermissions;
|
|
221
|
+
// { audio: true, video: true, maxVideoQuality: '1080p', maxFrameRate: 60,
|
|
222
|
+
// maxVideoQuality60: '720p', audioQualityMax: 'hd', maxVideoSubscriptions: 25, source: 'media' }
|
|
223
|
+
client.billingMode; // 'wallet' | 'legacy' | null (older servers)
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Offer only these in your UI. The server enforces them whatever a client sends;
|
|
227
|
+
the SDK never sends what it would refuse, and tells you with the server's own
|
|
228
|
+
codes:
|
|
229
|
+
|
|
230
|
+
- **Refused** (the call throws, nothing is produced): a kind the project
|
|
231
|
+
switched off -- `publish()` with such a track, `publishScreen()` without
|
|
232
|
+
video, `publishMusic()` without audio -- with `media-disabled`; and
|
|
233
|
+
`setAudioQuality('hd')` without HD audio, with `audio-quality-not-allowed`.
|
|
234
|
+
- **Capped** (the call goes on with the most the project allows, and `error`
|
|
235
|
+
carries a warning): HD audio asked for in `publish()` goes out standard
|
|
236
|
+
(`audio-quality-not-allowed`); 60 fps without 60 fps modes goes out at 30
|
|
237
|
+
(`frame-rate-not-allowed`); a 60 fps size that is not enabled goes out at the
|
|
238
|
+
largest that is (`video-quality-not-allowed`). A 30 fps quality above the
|
|
239
|
+
maximum is capped silently, as the server does.
|
|
240
|
+
- **Fan-out:** a session billed from the wallet receives at most
|
|
241
|
+
`maxVideoSubscriptions` videos at once (25 by default). Further videos wait,
|
|
242
|
+
with one `video-subscription-limit` warning each, and are received as others
|
|
243
|
+
end.
|
|
244
|
+
|
|
245
|
+
With an older server (no `media` in the join result) the `videoPolicy` alone
|
|
246
|
+
applies, as in 0.6.
|
|
247
|
+
|
|
151
248
|
### When the picture is soft
|
|
152
249
|
|
|
153
250
|
A soft or stuttering picture usually comes from the publisher's device (too
|
|
@@ -289,6 +386,12 @@ await client.stopMusic();
|
|
|
289
386
|
|
|
290
387
|
`setMicEnabled` and `setMusicEnabled` are independent, in both directions.
|
|
291
388
|
`publishMusic` also takes a `MediaStream` or a `MediaStreamTrack`.
|
|
389
|
+
`client.musicPublishing` is whether music is published at all, and
|
|
390
|
+
`client.musicEnabled` whether the audience hears it now.
|
|
391
|
+
|
|
392
|
+
Music is HD and free: it always goes out at 128 kbps stereo, also in a project
|
|
393
|
+
limited to standard audio, and the service never bills it. Sending or hearing
|
|
394
|
+
music never changes anyone's rate; the microphone and video alone decide it.
|
|
292
395
|
|
|
293
396
|
The host keeps hearing the music (`monitor`, on by default for an element). A
|
|
294
397
|
file from another origin must be served with CORS headers and loaded with
|
|
@@ -340,18 +443,123 @@ await client.getRoomState();
|
|
|
340
443
|
| `localMediaChanged` / `localStreamChanged` | your own mic, camera or stream changed |
|
|
341
444
|
| `connected` / `disconnected` | the socket came up or dropped; reconnection is automatic |
|
|
342
445
|
| `kicked` / `roomClosed` | you were removed, or the host ended the room |
|
|
446
|
+
| `mustReconnect` | the server moved this session (a promotion, a node lost); the client reconnects by itself, with the new token when one is given |
|
|
343
447
|
| `error` | a failure or recoverable warning such as `frame-rate-fallback`; inspect its code |
|
|
344
448
|
| `usageLimit` | your project ran out of minutes or hit a usage limit; the session ends at `endsAt` unless it is topped up |
|
|
345
449
|
| `videoLimited` | your camera video is held back by this device (`cpu`) or the upload (`bandwidth`), or that cleared (`none`) |
|
|
346
450
|
| `closed` | terminal — `replaced`, `kicked`, `room-closed` or `gave-up`, or `left` when your own `close()` ends the session |
|
|
451
|
+
| `connectionStateChanged` | `{ state, previous }`: `idle` → `connecting` → `connected` ⇄ `reconnecting` → `closed` |
|
|
452
|
+
| `participantUpdated` | someone changed their display metadata (`setMetadata`) |
|
|
453
|
+
| `claimChanged` | a slot was taken, went away, came back, was locked or freed: `{ key, identity, state, reason }` |
|
|
454
|
+
| `roomMetadataChanged` | a moderator changed the room metadata: `{ metadata, by }` |
|
|
455
|
+
| `walletLow` | wallet billing: what the project may spend covers less than the grace period (`{ remainingSeconds }`), or that is over (`{ remainingSeconds, cleared: true }`) |
|
|
456
|
+
| `tokenExpiring` | the token this client would reconnect with expires in about a minute and nobody refreshed it: `{ expiresAt, secondsLeft }` |
|
|
457
|
+
| `networkQuality` | about every 3 s while listened to: `{ level, rttMs, lossPct, availableKbps }` |
|
|
458
|
+
|
|
459
|
+
`on()` returns a function that removes the listener. `CLIENT_EVENTS` lists
|
|
460
|
+
every event name.
|
|
461
|
+
|
|
462
|
+
### Connection state
|
|
347
463
|
|
|
348
|
-
|
|
464
|
+
```ts
|
|
465
|
+
client.connectionState; // 'idle' | 'connecting' | 'connected' | 'reconnecting' | 'closed' (CONNECTION_STATES)
|
|
466
|
+
client.on('connectionStateChanged', ({ state, previous }) => render(state));
|
|
467
|
+
client.participants; // who is in the room, kept current from the roster events
|
|
468
|
+
client.remoteTracks; // [{ producerId, identity, kind, source, track, paused }] being received
|
|
469
|
+
client.info; // the join result, kept current: roster, slots, room metadata
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Tokens
|
|
473
|
+
|
|
474
|
+
A room token authorises the connection, not the session: a live session stays
|
|
475
|
+
up past its expiry, and the server pushes a fresh token before the one the
|
|
476
|
+
client holds lapses. Your backend can refresh it as well:
|
|
477
|
+
|
|
478
|
+
```ts
|
|
479
|
+
client.on('tokenExpiring', async ({ secondsLeft }) => {
|
|
480
|
+
const { token } = await fetch('/api/rtc/token', { method: 'POST' }).then((r) => r.json());
|
|
481
|
+
await client.updateToken(token); // { expiresAt } (ms)
|
|
482
|
+
});
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
`updateToken` sends the token on the live connection (`refreshToken`), where the
|
|
486
|
+
server checks it like a join token: `bad-token` for one it would refuse,
|
|
487
|
+
`token-mismatch` for another room or identity; the session then keeps its
|
|
488
|
+
token. While reconnecting, or before `connect()`, the token is kept for the
|
|
489
|
+
next join. An older server without `refreshToken` keeps it for the next
|
|
490
|
+
reconnect. `tokenExpiring` fires only when nobody refreshed the token: the
|
|
491
|
+
server stops when the account may no longer be used, and a dropped socket
|
|
492
|
+
cannot receive one.
|
|
493
|
+
|
|
494
|
+
### Wallet and usage notices
|
|
495
|
+
|
|
496
|
+
```ts
|
|
497
|
+
client.on('walletLow', ({ remainingSeconds, cleared }) => {
|
|
498
|
+
if (cleared) hideBanner();
|
|
499
|
+
else showBanner(`Credits run out in about ${remainingSeconds} s. Recharge to keep the call going.`);
|
|
500
|
+
});
|
|
501
|
+
client.on('usageLimit', ({ reason, endsAt }) => showCountdown(endsAt));
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
With wallet billing, `walletLow` warns while the funds the project may spend
|
|
505
|
+
(its own allocation, then the RTC allocation, then unallocated) cover less than
|
|
506
|
+
the grace period at the current burn; `usageLimit` is sent beside it for older
|
|
507
|
+
apps. The room closes with `roomClosed { reason: 'quota-exhausted' }` when the
|
|
508
|
+
funds reach zero unless the wallet is recharged first; a recharge sends
|
|
509
|
+
`walletLow { cleared: true }`, which also cancels the `usageLimit` countdown.
|
|
510
|
+
|
|
511
|
+
### Network quality
|
|
512
|
+
|
|
513
|
+
```ts
|
|
514
|
+
client.on('networkQuality', ({ level, rttMs, lossPct, availableKbps }) => showBars(level));
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
Sampled from the media transports' statistics about every 3 s, only while
|
|
518
|
+
something listens and the session is connected. `rttMs` is the round trip to
|
|
519
|
+
the media server, `lossPct` the packets lost over the last interval in the
|
|
520
|
+
worse direction (sending or receiving), `availableKbps` the browser's bandwidth
|
|
521
|
+
estimate (upload while publishing). Each is `null` until known. The level:
|
|
522
|
+
|
|
523
|
+
| `level` | Round trip | and loss |
|
|
524
|
+
| --- | --- | --- |
|
|
525
|
+
| `excellent` | under 150 ms | under 1 % |
|
|
526
|
+
| `good` | under 300 ms | under 3 % |
|
|
527
|
+
| `poor` | under 500 ms | under 8 % |
|
|
528
|
+
| `bad` | anything worse | |
|
|
529
|
+
|
|
530
|
+
An unknown value does not lower the level. Bandwidth is reported, not graded:
|
|
531
|
+
`videoLimited` says when the camera is held back by the device or the upload.
|
|
532
|
+
|
|
533
|
+
### Slots and room metadata
|
|
534
|
+
|
|
535
|
+
A slot is a named thing in the room that one participant holds at a time: a
|
|
536
|
+
seat on a board, a guest spot. Keys are yours.
|
|
537
|
+
|
|
538
|
+
```ts
|
|
539
|
+
await client.claim('seat-3'); // take it; claim('seat-3', identity) grants it (moderators)
|
|
540
|
+
await client.release('seat-3');
|
|
541
|
+
await client.blockSlot('seat-9'); // moderators: lock it; refused with slot-occupied while held
|
|
542
|
+
await client.unblockSlot('seat-9');
|
|
543
|
+
await client.setMetadata({ name: 'Ana' }); // your display metadata; the room hears participantUpdated
|
|
544
|
+
await client.setRoomMetadata({ seats: 10 }, { requireFree: ['seat-11', 'seat-12'] }); // moderators; persisted
|
|
545
|
+
|
|
546
|
+
client.info.claims; // [{ key, identity, state: 'held' | 'away' }]
|
|
547
|
+
client.info.blockedSlots; // ['seat-9']
|
|
548
|
+
client.info.metadata; // the room metadata
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
**Draw `away` as taken (greyed), never as free:** the holder's connection
|
|
552
|
+
dropped and the slot is kept for them for about a minute. A refused
|
|
553
|
+
`setRoomMetadata` names the slots in the way in `error.data.slots`.
|
|
349
554
|
|
|
350
555
|
### Reconnection
|
|
351
556
|
|
|
352
557
|
Handled for you. A dropped socket is retried with backoff, the session is
|
|
353
|
-
rejoined, and if you were publishing, your media is published again
|
|
354
|
-
with `gave-up` means it
|
|
558
|
+
rejoined, and if you were publishing, your media is published again (with the
|
|
559
|
+
same quality, frame rate and audio quality). `closed` with `gave-up` means it
|
|
560
|
+
stopped trying: after eight attempts, or at once for a join refused with a code
|
|
561
|
+
retrying cannot fix (`isTerminalError`: the room ended, the token is wrong, you
|
|
562
|
+
were removed, the account ran out).
|
|
355
563
|
|
|
356
564
|
`replaced` means the same identity joined the same room somewhere else, and
|
|
357
565
|
this connection lost. Do not reconnect on it: the two would take turns evicting
|
|
@@ -443,6 +651,8 @@ the user clicks "go live", and keep it out of logs and analytics.
|
|
|
443
651
|
`start()` rejects with `WhipError` if the media server refuses. `isRefused`
|
|
444
652
|
means the URL itself was not accepted — expired, for another stream, or the
|
|
445
653
|
account is out of minutes — and a retry with the same URL is refused again.
|
|
654
|
+
A media server that cannot be reached, does not answer within 15 s, or drops
|
|
655
|
+
the connection while answering is a `WhipError` too, with `status` 0.
|
|
446
656
|
|
|
447
657
|
Video is offered as **H.264 only**. The media server repackages H.264 into HLS
|
|
448
658
|
untouched; any other codec makes it transcode every frame. A browser with no
|
|
@@ -487,8 +697,23 @@ if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
|
|
487
697
|
## Errors
|
|
488
698
|
|
|
489
699
|
Server refusals reject with `RpcError` (rooms) or `ChatRpcError` (`ChatClient`),
|
|
490
|
-
both carrying a machine-readable `code
|
|
491
|
-
|
|
700
|
+
both carrying a machine-readable `code`; the SDK's own failures and warnings
|
|
701
|
+
are `RpcError`s too. Switch on `code`, never on the message. `RpcError.data`
|
|
702
|
+
is what the server attached to act on a refusal (`{ slots }` for
|
|
703
|
+
`slot-occupied`).
|
|
704
|
+
|
|
705
|
+
Every code is in one registry shared by all VoltKit SDKs:
|
|
706
|
+
|
|
707
|
+
```ts
|
|
708
|
+
import { ERROR_CODES, errorInfo, isTerminalError } from '@voltkit-rtc/client';
|
|
709
|
+
|
|
710
|
+
errorInfo('quota-exhausted'); // { origin: 'server', terminal: true, retryable: false }
|
|
711
|
+
isTerminalError(code); // a join refused with it is not retried
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
A newer server may send a code this release does not know: it is passed through
|
|
715
|
+
unchanged, and treated as not terminal. The registry with every meaning is in
|
|
716
|
+
the repository's `docs/SDK-CONTRACT.md`, the wire codes in the
|
|
492
717
|
[API reference](https://voltkit.in/docs/api-reference).
|
|
493
718
|
|
|
494
719
|
## Help
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"broadcast.d.ts","sourceRoot":"","sources":["../../src/broadcast.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAc,KAAK,UAAU,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAE5E,yDAAyD;AACzD,qBAAa,SAAU,SAAQ,KAAK;IAItB,QAAQ,CAAC,MAAM,EAAE,MAAM;IAHnC;;OAEG;gBACkB,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAKpD;;;;OAIG;IACH,IAAI,SAAS,IAAI,OAAO,CAEvB;CACF;AAED,MAAM,MAAM,cAAc,GACtB,MAAM,GACN,YAAY;AACd,4CAA4C;GAC1C,MAAM;AACR,0FAA0F;GACxF,aAAa,GACb,QAAQ,GACR,SAAS,CAAC;AAEd,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IACvC;;;OAGG;IACH,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,qBAAqB;IACpC,gFAAgF;IAChF,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,wEAAwE;IACxE,WAAW,CAAC,EAAE,sBAAsB,CAAC;IACrC,yFAAyF;IACzF,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAUD;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,SAAS,SAAkB,GAC1B,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"broadcast.d.ts","sourceRoot":"","sources":["../../src/broadcast.ts"],"names":[],"mappings":"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"}
|
package/dist/cjs/broadcast.js
CHANGED
|
@@ -43,23 +43,32 @@ const HELPER_FORMATS = new Set(['video/rtx', 'video/red', 'video/ulpfec', 'video
|
|
|
43
43
|
* resource the server names for ending it.
|
|
44
44
|
*/
|
|
45
45
|
async function whipOffer(whipUrl, offerSdp, timeoutMs = WHIP_TIMEOUT_MS) {
|
|
46
|
+
// One deadline for the request and the whole answer: the signal stays
|
|
47
|
+
// armed while the body is read.
|
|
48
|
+
const signal = AbortSignal.timeout(timeoutMs);
|
|
49
|
+
// Never echo the URL or the error: the URL carries the publish token.
|
|
50
|
+
const failed = (err, otherwise) => new WhipError(0, signal.aborted || err?.name === 'TimeoutError' ? 'the media server did not answer in time' : otherwise);
|
|
46
51
|
let res;
|
|
47
52
|
try {
|
|
48
53
|
res = await fetch(whipUrl, {
|
|
49
54
|
method: 'POST',
|
|
50
55
|
headers: { 'Content-Type': 'application/sdp', Accept: 'application/sdp' },
|
|
51
56
|
body: offerSdp,
|
|
52
|
-
signal
|
|
57
|
+
signal,
|
|
53
58
|
});
|
|
54
59
|
}
|
|
55
60
|
catch (err) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
throw failed(err, 'could not reach the media server');
|
|
62
|
+
}
|
|
63
|
+
let body;
|
|
64
|
+
try {
|
|
65
|
+
// A deadline or a connection lost after the headers is the same failure
|
|
66
|
+
// as one before them, and is reported the same way.
|
|
67
|
+
body = await res.text();
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
throw failed(err, 'the connection to the media server was lost');
|
|
61
71
|
}
|
|
62
|
-
const body = await res.text();
|
|
63
72
|
if (res.status !== 201 && res.status !== 200) {
|
|
64
73
|
const line = body.split('\n')[0]?.trim().slice(0, 200);
|
|
65
74
|
throw new WhipError(res.status, line || 'the media server refused the stream');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"broadcast.js","sourceRoot":"","sources":["../../src/broadcast.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAiEH,
|
|
1
|
+
{"version":3,"file":"broadcast.js","sourceRoot":"","sources":["../../src/broadcast.ts"],"names":[],"mappings":"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"}
|
package/dist/cjs/chat.d.ts
CHANGED
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Chat for the orchestrator's signaling protocol.
|
|
3
|
-
*
|
|
4
|
-
* A channel shares its name with the room of the same name, so there are two
|
|
5
|
-
* ways into one conversation: `StreamClient` carries chat over the socket it
|
|
6
|
-
* already holds for media, and `ChatClient` here opens a socket that carries
|
|
7
|
-
* nothing else -- for an audience that is watching a broadcast over a CDN and
|
|
8
|
-
* has no reason to be on an SFU.
|
|
9
|
-
*/
|
|
10
1
|
import type { Role } from './index.js';
|
|
11
2
|
export interface ChatMessage {
|
|
12
3
|
/** Monotonic within a channel, so the oldest id held is a paging cursor. */
|
|
@@ -102,6 +93,11 @@ export declare class ChatClient {
|
|
|
102
93
|
private token;
|
|
103
94
|
private joinResult;
|
|
104
95
|
private closedByUs;
|
|
96
|
+
/**
|
|
97
|
+
* Bumped by close(). A connect() under way when it ran -- the app's, or a
|
|
98
|
+
* reconnect's -- sees the change after its await and stops.
|
|
99
|
+
*/
|
|
100
|
+
private lifecycle;
|
|
105
101
|
private reconnecting;
|
|
106
102
|
private reconnectAttempt;
|
|
107
103
|
/** Set by the first successful join. Only a session that has joined is reconnected. */
|
|
@@ -114,6 +110,12 @@ export declare class ChatClient {
|
|
|
114
110
|
connect(): Promise<ChatJoinResult>;
|
|
115
111
|
private openSocket;
|
|
116
112
|
private detachSocket;
|
|
113
|
+
/**
|
|
114
|
+
* A reconnect that ends the session lets go of its socket: a refused join
|
|
115
|
+
* leaves it open, and it would otherwise stay attached, and sending, after
|
|
116
|
+
* closed.
|
|
117
|
+
*/
|
|
118
|
+
private releaseSocket;
|
|
117
119
|
/** Single-flight, with backoff: the same shape as the room client's. */
|
|
118
120
|
private scheduleReconnect;
|
|
119
121
|
close(): void;
|
package/dist/cjs/chat.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/chat.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/chat.ts"],"names":[],"mappings":"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"}
|