@voltkit-rtc/client 0.2.0 → 0.4.0
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 +112 -0
- package/README.md +147 -3
- package/dist/cjs/chat.d.ts +2 -0
- package/dist/cjs/chat.d.ts.map +1 -1
- package/dist/cjs/chat.js +23 -4
- package/dist/cjs/chat.js.map +1 -1
- package/dist/cjs/device.d.ts +85 -0
- package/dist/cjs/device.d.ts.map +1 -0
- package/dist/cjs/device.js +134 -0
- package/dist/cjs/device.js.map +1 -0
- package/dist/cjs/index.d.ts +184 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +546 -32
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/quality.d.ts +74 -0
- package/dist/cjs/quality.d.ts.map +1 -0
- package/dist/cjs/quality.js +115 -0
- package/dist/cjs/quality.js.map +1 -0
- package/dist/cjs/stats.d.ts +151 -0
- package/dist/cjs/stats.d.ts.map +1 -0
- package/dist/cjs/stats.js +243 -0
- package/dist/cjs/stats.js.map +1 -0
- package/dist/esm/chat.d.ts +2 -0
- package/dist/esm/chat.d.ts.map +1 -1
- package/dist/esm/chat.js +23 -4
- package/dist/esm/chat.js.map +1 -1
- package/dist/esm/device.d.ts +85 -0
- package/dist/esm/device.d.ts.map +1 -0
- package/dist/esm/device.js +122 -0
- package/dist/esm/device.js.map +1 -0
- package/dist/esm/index.d.ts +184 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +541 -31
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/quality.d.ts +74 -0
- package/dist/esm/quality.d.ts.map +1 -0
- package/dist/esm/quality.js +107 -0
- package/dist/esm/quality.js.map +1 -0
- package/dist/esm/stats.d.ts +151 -0
- package/dist/esm/stats.d.ts.map +1 -0
- package/dist/esm/stats.js +232 -0
- package/dist/esm/stats.js.map +1 -0
- package/package.json +3 -2
- package/src/chat.ts +21 -4
- package/src/device.ts +168 -0
- package/src/index.ts +627 -29
- package/src/quality.ts +126 -0
- package/src/stats.ts +328 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,117 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
Sharper video, above all from phones. Nothing to change to upgrade: every 0.3.0
|
|
6
|
+
call works as before, with new defaults.
|
|
7
|
+
|
|
8
|
+
- **Higher bitrates.** Each layer gets about 4 Mbps at 1080p, 2.5 Mbps at
|
|
9
|
+
720p, 1.5 Mbps at 540p, 1 Mbps at 480p, 700 kbps at 360p and 400 kbps at
|
|
10
|
+
240p (were 2.5 Mbps, 1.8 Mbps, 1.2 Mbps, 750, 600 and 250 kbps). At 720p
|
|
11
|
+
that brought VP8's quantiser down from about 64 to 55: finer detail, most
|
|
12
|
+
of all in motion. A new stream's bandwidth estimate starts at 1.5 Mbps (was
|
|
13
|
+
1 Mbps). The service's per-publisher caps rose to match (4 Mbps up to 720p,
|
|
14
|
+
7 Mbps with 1080p), and viewers of 720p now start on the top layer instead
|
|
15
|
+
of taking about 15 s to climb to it.
|
|
16
|
+
- **Phones keep the full picture.** New `PublishOptions.layers` (1, 2 or 3).
|
|
17
|
+
Phones and tablets now send two layers (half and full size) by default,
|
|
18
|
+
computers three as before. A busy phone shrinks its picture and then sends
|
|
19
|
+
fewer layers, dropping the top one: from three, viewers of a 720p phone got
|
|
20
|
+
180×320; from two, the full picture survives.
|
|
21
|
+
- **H.264 on phones.** New `PublishOptions.codec`: `'auto'` (the default)
|
|
22
|
+
sends H.264 on phones and tablets that encode it in hardware and VP8
|
|
23
|
+
everywhere else; `'vp8'` and `'h264'` force one. If H.264 cannot be used,
|
|
24
|
+
VP8 is sent and the publish goes on; a forced `'h264'` that falls back also
|
|
25
|
+
fires `error`. A viewer whose browser cannot decode H.264 (rare: a few
|
|
26
|
+
browser builds leave it out) cannot watch a phone sending it: force `'vp8'`
|
|
27
|
+
if your audience uses such browsers.
|
|
28
|
+
- New `PublishOptions.degradationPreference`: what the encoder gives up first
|
|
29
|
+
on a busy device. Unset leaves the browser's default.
|
|
30
|
+
- **`getVideoStats()`**: what the camera is sending, layer by layer, and why
|
|
31
|
+
it is less than asked (`qualityLimitation`: `cpu` is the device,
|
|
32
|
+
`bandwidth` the upload). **`getReceiveStats(producerId)`**: what this client
|
|
33
|
+
receives of someone's video.
|
|
34
|
+
- **`videoLimited` event**: the camera video is being held back by the device
|
|
35
|
+
(`cpu`), the upload (`bandwidth`) or something else (`other`), or that has
|
|
36
|
+
cleared (`none`). It fires once a reason has held for about 4 s, and is
|
|
37
|
+
checked only while you listen. Tell the publisher, so they know it is their
|
|
38
|
+
device or connection.
|
|
39
|
+
- **`replaceVideoTrack(track)`**: send another video track, such as a canvas
|
|
40
|
+
with effects or the raw camera again. Viewers see no pause when the new
|
|
41
|
+
track takes the same layers. Your own stream is never modified, and a
|
|
42
|
+
track replaced while the camera was paused comes back to you switched on.
|
|
43
|
+
- **`setPreferredLayers(producerId, spatialLayer, temporalLayer?)`**: receive
|
|
44
|
+
a smaller copy of someone's video for a small tile, as the Flutter and
|
|
45
|
+
native SDKs already could. Layer 0 is the smallest copy sent; at 720p the
|
|
46
|
+
640×360 copy needs about 0.76 Mbps instead of 2.6 for the full picture. The
|
|
47
|
+
choice is kept across reconnects and forgotten when the track ends.
|
|
48
|
+
- `setVideoQuality`, `replaceVideoTrack` and publishing now change the camera
|
|
49
|
+
producer one at a time, so quick changes cannot leave two of them, and an
|
|
50
|
+
`unpublish()` in the middle of one leaves none.
|
|
51
|
+
- Upload needed rises with the bitrates: about 3.4 Mbps for 720p from a
|
|
52
|
+
computer (3.2 from a phone), 6 Mbps for 1080p (5.5 from a phone) and
|
|
53
|
+
1.4 Mbps for 480p.
|
|
54
|
+
- New exports: the `LayerCount`, `CodecPreference`, `VideoSendStats`,
|
|
55
|
+
`VideoLayerStats`, `VideoReceiveStats`, `VideoLimitedEvent` and
|
|
56
|
+
`VideoLimitReason` types. `videoEncodings` takes the most layers to send as
|
|
57
|
+
an optional fourth argument.
|
|
58
|
+
- **Fix: reconnecting gives up when it should.** The attempt count restarted
|
|
59
|
+
whenever the socket opened, so a join refused with a code worth retrying
|
|
60
|
+
(`no-capacity`, `no-node`, `internal`) was retried about twice a second,
|
|
61
|
+
forever, and `closed` with `gave-up` never came: in a full cluster every
|
|
62
|
+
client kept at it. The count now restarts only once a join succeeds, the
|
|
63
|
+
gaps keep growing (half a second, doubling to 15 s), and after eight failed
|
|
64
|
+
attempts in a row the client stops with `closed` (`gave-up`). A connection
|
|
65
|
+
that drops again while a reconnect is restoring the session is retried
|
|
66
|
+
too; it was left disconnected, with no `closed`. `ChatClient` counted the
|
|
67
|
+
same way and is fixed the same way.
|
|
68
|
+
- **Fix: a camera that is off stays off, on both ends.** A track handed to
|
|
69
|
+
`publish()` switched off, a camera switched off before a reconnect, or a
|
|
70
|
+
quality change or track swap to other layers could leave the camera paused
|
|
71
|
+
in the client but live on the server, so viewers got black video under a
|
|
72
|
+
camera shown as on (and silence, for a microphone or music switched off
|
|
73
|
+
before a reconnect). The server is now paused too; a camera producer that
|
|
74
|
+
is replaced starts in the camera's state, and while the camera is off no
|
|
75
|
+
frame of the new track is sent; a track swapped in during a reconnect, and
|
|
76
|
+
devices a reconnect has to ask for again, keep a camera that was off, off.
|
|
77
|
+
`camEnabled`, `micEnabled` and `localMediaChanged` report as before.
|
|
78
|
+
- **Fix:** `unpublish()` while `publish()` or `publishMusic()` is still
|
|
79
|
+
making the microphone or music producer no longer leaves it published; the
|
|
80
|
+
camera was already covered. What was being made is closed and that call
|
|
81
|
+
rejects. A reconnect's republish under way when `unpublish()` runs
|
|
82
|
+
publishes nothing either.
|
|
83
|
+
- **Fix: `unpublish()` forgets the devices.** It kept the capture constraints
|
|
84
|
+
given to `publish()`, so after `unpublish()` and then `publishMusic()`, a
|
|
85
|
+
reconnect asked for the camera and microphone again and published them.
|
|
86
|
+
Music published after `unpublish()` now reconnects alone.
|
|
87
|
+
- **Fix:** `publish()` and `unpublish()` act in the order they are called. A
|
|
88
|
+
`publish()` or `publishMusic()` called while an `unpublish()` was still
|
|
89
|
+
waiting on the server had its new stream stopped and its state cleared when
|
|
90
|
+
that `unpublish()` finished. `unpublish()` now makes all its changes at once
|
|
91
|
+
and only then waits for the server.
|
|
92
|
+
- **Fix:** a first `connect()` that fails at the join closes its socket and
|
|
93
|
+
starts no reconnect loop; only a session that has joined is reconnected.
|
|
94
|
+
Before, the server's join deadline closed that socket about 15 s later, and
|
|
95
|
+
the client began reconnecting a session the app had already been told had
|
|
96
|
+
failed. `ChatClient` too.
|
|
97
|
+
|
|
98
|
+
## 0.3.0
|
|
99
|
+
|
|
100
|
+
- **Video quality.** `publish(stream, constraints, { quality })` takes
|
|
101
|
+
`'1080p'`, `'720p'` or `'480p'`, and `setVideoQuality(quality)` changes it
|
|
102
|
+
while live. `videoPolicy` reports what the project may publish (from the
|
|
103
|
+
join result's new `video` field) and `videoQuality` what is being sent.
|
|
104
|
+
1080p needs the project to allow it (it does during the free trial); asking
|
|
105
|
+
for more sends the highest allowed.
|
|
106
|
+
- **Simulcast layers follow the real picture size.** Smaller pictures (480p,
|
|
107
|
+
portrait phones, 4:3 webcams) used to be sent with three layers that the
|
|
108
|
+
browser could not all send, and it dropped the top ones, so viewers got half
|
|
109
|
+
or a quarter of the resolution. Now each picture gets the layers it can
|
|
110
|
+
really send. 720p at 1280×720 is unchanged (200 kbps, 600 kbps, 1.8 Mbps).
|
|
111
|
+
- New exports: `videoEncodings`, `layerBitrate`, `allowedQuality`,
|
|
112
|
+
`VIDEO_QUALITIES` and the `VideoQuality`, `VideoPolicy`, `VideoEncoding` and
|
|
113
|
+
`PublishOptions` types.
|
|
114
|
+
|
|
3
115
|
## 0.2.0
|
|
4
116
|
|
|
5
117
|
First release on npm, as `@voltkit-rtc/client`. Earlier builds were shared as
|
package/README.md
CHANGED
|
@@ -47,8 +47,8 @@ client.on('closed', (reason) => leaveScreen(reason)); // terminal; nothing f
|
|
|
47
47
|
const joined = await client.connect();
|
|
48
48
|
|
|
49
49
|
if (joined.role === 'host' || joined.role === 'cohost') {
|
|
50
|
-
const media = await navigator.mediaDevices.getUserMedia({ audio: true, video:
|
|
51
|
-
await client.publish(media); //
|
|
50
|
+
const media = await navigator.mediaDevices.getUserMedia({ audio: true, video: { width: 1280, height: 720 } });
|
|
51
|
+
await client.publish(media); // 720p: 3 simulcast layers from a computer, 2 from a phone
|
|
52
52
|
}
|
|
53
53
|
```
|
|
54
54
|
|
|
@@ -69,6 +69,149 @@ client.publishing; client.micEnabled; client.camEnabled; client.local; // curr
|
|
|
69
69
|
A `viewer` cannot publish. That is enforced at the media server, not in this
|
|
70
70
|
package — a tampered client gets an error, not a stream.
|
|
71
71
|
|
|
72
|
+
`publish(media, constraints, options)` takes these options. The defaults suit
|
|
73
|
+
phones and computers alike; they are kept for a reconnect's republish.
|
|
74
|
+
|
|
75
|
+
| Option | Default | What it does |
|
|
76
|
+
| --- | --- | --- |
|
|
77
|
+
| `quality` | the highest the project allows | `'1080p'`, `'720p'` or `'480p'`; see [Video quality](#video-quality) |
|
|
78
|
+
| `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 |
|
|
79
|
+
| `codec` | `'auto'` | `'auto'` sends H.264 on phones and tablets that encode it in hardware, VP8 elsewhere. `'vp8'` or `'h264'` forces one; a forced H.264 the browser cannot send is VP8, and fires `error` |
|
|
80
|
+
| `degradationPreference` | the browser's | what the encoder gives up first on a busy device: `'maintain-resolution'` (frame rate goes first), `'maintain-framerate'` or `'balanced'` |
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
await client.publish(media, undefined, { quality: '720p', layers: 2, codec: 'auto', degradationPreference: 'maintain-resolution' });
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Chrome also reads the trade-off from the track itself:
|
|
87
|
+
`track.contentHint = 'detail'` keeps the resolution, `'motion'` the frame rate.
|
|
88
|
+
A viewer whose browser cannot decode the codec cannot watch, so force `'vp8'`
|
|
89
|
+
if your audience uses browsers without H.264 (rare).
|
|
90
|
+
|
|
91
|
+
To send another video track while live, such as a canvas with effects drawn on
|
|
92
|
+
it or the raw camera again:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
await client.replaceVideoTrack(canvas.captureStream(30).getVideoTracks()[0]);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
When the new track takes the same layers as the old one (the same size is the
|
|
99
|
+
safe choice), viewers see no pause; otherwise the camera's producer is replaced
|
|
100
|
+
and they see a brief one. A paused camera stays paused. Your own stream is not
|
|
101
|
+
modified: the client keeps one of its own (`client.local`, announced by
|
|
102
|
+
`localStreamChanged`) with the new track, and a reconnect republishes that. The
|
|
103
|
+
track you replaced is yours again: it is not stopped, and if pausing the camera
|
|
104
|
+
had switched it off, it is switched back on.
|
|
105
|
+
|
|
106
|
+
### Video quality
|
|
107
|
+
|
|
108
|
+
Choose 1080p, 720p or 480p when publishing, or change it while live:
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
const media = await navigator.mediaDevices.getUserMedia({ audio: true, video: { width: 1920, height: 1080 } });
|
|
112
|
+
await client.publish(media, undefined, { quality: '1080p' });
|
|
113
|
+
await client.setVideoQuality('480p'); // resolves to the quality actually used
|
|
114
|
+
|
|
115
|
+
client.videoPolicy; // { maxQuality: '720p' | '1080p', maxBitrate } for this project
|
|
116
|
+
client.videoQuality; // what is being sent now
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
| Quality | Layers from a computer | From a phone or tablet | Upload needed |
|
|
120
|
+
|---|---|---|---|
|
|
121
|
+
| 1080p | 480×270 @ 400 kbps · 960×540 @ 1.5 Mbps · 1920×1080 @ **4 Mbps** | the top two | about 6 Mbps (phone 5.5); 8 Mbps or more to be safe |
|
|
122
|
+
| 720p | 320×180 @ 200 kbps · 640×360 @ 700 kbps · 1280×720 @ **2.5 Mbps** | the top two | about 3.4 Mbps (phone 3.2); 4 Mbps or more to be safe |
|
|
123
|
+
| 480p | 427×240 @ 400 kbps · 854×480 @ **1 Mbps** | the same two | about 1.4 Mbps; 2 Mbps or more to be safe |
|
|
124
|
+
|
|
125
|
+
- 720p and 480p are available to every project. 1080p is available to projects
|
|
126
|
+
that have it enabled (request it from your project's Settings in the VoltKit
|
|
127
|
+
dashboard), and to your first project during the free trial. Asking for more
|
|
128
|
+
than the project allows sends the highest it does allow.
|
|
129
|
+
- The default is the highest the project allows. The picture is scaled down to
|
|
130
|
+
the quality, never up: capture at least that size for the full picture.
|
|
131
|
+
- The layers follow the picture's real size (a portrait phone, a 4:3 webcam),
|
|
132
|
+
so the browser sends every layer requested. A portrait 720p phone sends
|
|
133
|
+
360×640 and 720×1280.
|
|
134
|
+
- At 720p and 480p each viewer starts on the top layer and gets a lower one
|
|
135
|
+
only while their connection cannot carry it. 1080p's top layer can need more
|
|
136
|
+
than a viewer's starting estimate (3 Mbps), so a 1080p viewer may start one
|
|
137
|
+
layer down and move up as their connection allows.
|
|
138
|
+
- The server caps each publisher's incoming bitrate for the project's tier
|
|
139
|
+
(4 Mbps up to 720p, 7 Mbps with 1080p, audio included), whatever client is
|
|
140
|
+
used.
|
|
141
|
+
|
|
142
|
+
The full guide, with data use:
|
|
143
|
+
[voltkit.in/docs/video-quality](https://voltkit.in/docs/video-quality).
|
|
144
|
+
|
|
145
|
+
### When the picture is soft
|
|
146
|
+
|
|
147
|
+
A soft or stuttering picture usually comes from the publisher's device (too
|
|
148
|
+
busy to encode) or their upload (too slow for the top layer), not from the
|
|
149
|
+
service. The client can tell you which.
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
const stats = await client.getVideoStats(); // null when no camera is published
|
|
153
|
+
// { codec: 'H264', quality: '720p', width: 720, height: 1280, fps: 30, bitrate: 2400000,
|
|
154
|
+
// qualityLimitation: 'none', availableOutgoingBitrate: 3900000, layers: [ ... ] }
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
The top-level fields describe the biggest layer going out; `layers` lists each
|
|
158
|
+
one (`active`, size, frame rate, bitrate). `qualityLimitation` is the browser's
|
|
159
|
+
reason for sending less than asked: `cpu` is the device, `bandwidth` the
|
|
160
|
+
upload, `none` neither (then look at the camera and the light). Bitrates are
|
|
161
|
+
averaged since your previous call, so call it every second or two; the first
|
|
162
|
+
call reports 0.
|
|
163
|
+
|
|
164
|
+
`videoLimited` tells you when that changes, so you can tell the publisher:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
client.on('videoLimited', ({ reason }) => {
|
|
168
|
+
if (reason === 'cpu') showNotice('Your device is busy, so the stream is softer. Turn off effects or switch to 480p.');
|
|
169
|
+
else if (reason === 'bandwidth') showNotice('Your upload is slow, so viewers get a lighter picture.');
|
|
170
|
+
else hideNotice(); // 'none': cleared; 'other': rare
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
It fires once a new reason has held for about 4 seconds, so brief spikes stay
|
|
175
|
+
quiet, and never fires `none` first. The client checks every 2 seconds, and
|
|
176
|
+
only while a camera is published and something listens. `unpublish()` fires
|
|
177
|
+
`none` if a limitation was showing.
|
|
178
|
+
|
|
179
|
+
On a viewer, `getReceiveStats(producerId)` (the `producerId` from the `track`
|
|
180
|
+
event) says what arrives: size, frame rate, bitrate, `packetsLost`, `jitter`
|
|
181
|
+
and, where the browser counts them, `freezeCount`. A viewer receiving a
|
|
182
|
+
smaller picture than the publisher's biggest layer is on a lower one, picked
|
|
183
|
+
for their own connection; if every viewer is, look at the publisher's
|
|
184
|
+
`getVideoStats()`.
|
|
185
|
+
|
|
186
|
+
The [troubleshooting guide](https://voltkit.in/docs/troubleshooting) lists the
|
|
187
|
+
usual causes and what to do about each.
|
|
188
|
+
|
|
189
|
+
### Small tiles
|
|
190
|
+
|
|
191
|
+
Each viewer gets the biggest layer their connection carries, which a thumbnail
|
|
192
|
+
or a row of co-host tiles does not need. Ask for a smaller one with the
|
|
193
|
+
`producerId` from the `track` event:
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
client.on('track', ({ kind, producerId, track }) => {
|
|
197
|
+
if (kind !== 'video') return;
|
|
198
|
+
showVideo(producerId, track);
|
|
199
|
+
if (isSmallTile(producerId)) client.setPreferredLayers(producerId, 0).catch(console.warn);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
await client.setPreferredLayers(producerId, 2); // the tile grew: the biggest layer again
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Layer 0 is the smallest copy the publisher sends. At 720p a computer sends
|
|
206
|
+
three (320×180, 640×360 and 1280×720) and a phone two (640×360 and 1280×720);
|
|
207
|
+
a layer above the biggest means the biggest. The 640×360 copy needs about
|
|
208
|
+
0.76 Mbps, the full picture about 2.6. An optional third argument, the
|
|
209
|
+
temporal layer, lowers the frame rate as well; without it the full frame rate
|
|
210
|
+
is kept. It is the most this viewer is sent: a connection that cannot carry it
|
|
211
|
+
still gets less. The choice is kept across reconnects and forgotten when the
|
|
212
|
+
track ends, and `setPreferredLayers` rejects for a video this client is not
|
|
213
|
+
receiving.
|
|
214
|
+
|
|
72
215
|
### Music
|
|
73
216
|
|
|
74
217
|
A host can play music to the room from inside the page. It does not go through
|
|
@@ -138,7 +281,8 @@ await client.getRoomState();
|
|
|
138
281
|
| `kicked` / `roomClosed` | you were removed, or the host ended the room |
|
|
139
282
|
| `error` | something failed that the SDK could not recover from by itself |
|
|
140
283
|
| `usageLimit` | your project ran out of minutes or hit a usage limit; the session ends at `endsAt` unless it is topped up |
|
|
141
|
-
| `
|
|
284
|
+
| `videoLimited` | your camera video is held back by this device (`cpu`) or the upload (`bandwidth`), or that cleared (`none`) |
|
|
285
|
+
| `closed` | terminal — `replaced`, `kicked`, `room-closed` or `gave-up`, or `left` when your own `close()` ends the session |
|
|
142
286
|
|
|
143
287
|
`on()` returns a function that removes the listener.
|
|
144
288
|
|
package/dist/cjs/chat.d.ts
CHANGED
|
@@ -104,6 +104,8 @@ export declare class ChatClient {
|
|
|
104
104
|
private closedByUs;
|
|
105
105
|
private reconnecting;
|
|
106
106
|
private reconnectAttempt;
|
|
107
|
+
/** Set by the first successful join. Only a session that has joined is reconnected. */
|
|
108
|
+
private joinedOnce;
|
|
107
109
|
constructor(wsUrl: string, token: string);
|
|
108
110
|
on<K extends keyof ChatClientEvents>(event: K, fn: ChatClientEvents[K]): () => void;
|
|
109
111
|
private emit;
|
package/dist/cjs/chat.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/chat.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,WAAW,WAAW;IAC1B,4EAA4E;IAC5E,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iFAAiF;IACjF,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,KAAK,EAAE,OAAO,CAAC;IACf,mCAAmC;IACnC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,IAAI,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,8CAA8C;IAC9C,QAAQ,EAAE,WAAW,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,IAAI,CAAC;IAClC,cAAc,EAAE,CAAC,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACxD,SAAS,EAAE,CAAC,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACzE,MAAM,EAAE,CAAC,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;CAC5D;AAED,MAAM,WAAW,gBAAiB,SAAQ,UAAU;IAClD,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,MAAM,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC;IACzC,KAAK,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAC;IAC5B,+EAA+E;IAC/E,MAAM,EAAE,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,KAAK,IAAI,CAAC;IACvD,4EAA4E;IAC5E,UAAU,EAAE,CAAC,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACnF;AAED,2EAA2E;AAC3E,qBAAa,YAAa,SAAQ,KAAK;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAInD;AAyBD;;;GAGG;AACH,qBAAa,UAAU;
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/chat.ts"],"names":[],"mappings":"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"}
|
package/dist/cjs/chat.js
CHANGED
|
@@ -39,6 +39,8 @@ class ChatClient {
|
|
|
39
39
|
closedByUs = false;
|
|
40
40
|
reconnecting = false;
|
|
41
41
|
reconnectAttempt = 0;
|
|
42
|
+
/** Set by the first successful join. Only a session that has joined is reconnected. */
|
|
43
|
+
joinedOnce = false;
|
|
42
44
|
constructor(wsUrl, token) {
|
|
43
45
|
this.wsUrl = wsUrl;
|
|
44
46
|
this.token = token;
|
|
@@ -67,8 +69,24 @@ class ChatClient {
|
|
|
67
69
|
return this.joinResult;
|
|
68
70
|
}
|
|
69
71
|
async connect() {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
let result;
|
|
73
|
+
try {
|
|
74
|
+
await this.openSocket();
|
|
75
|
+
result = (await this.rpc('join', { token: this.token }));
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
// Never joined: the app has the error. Left open, the socket would be
|
|
79
|
+
// closed by the server's join deadline, and that would start
|
|
80
|
+
// reconnecting a session that never began.
|
|
81
|
+
if (!this.joinedOnce)
|
|
82
|
+
this.detachSocket();
|
|
83
|
+
throw err;
|
|
84
|
+
}
|
|
85
|
+
// Joined: the next drop gets every reconnect attempt again. Not when the
|
|
86
|
+
// socket opens, or a join refused with a code worth retrying never uses
|
|
87
|
+
// them up and is retried about twice a second, forever.
|
|
88
|
+
this.reconnectAttempt = 0;
|
|
89
|
+
this.joinedOnce = true;
|
|
72
90
|
this.joinResult = result;
|
|
73
91
|
this.emit('joined', result);
|
|
74
92
|
return result;
|
|
@@ -82,7 +100,6 @@ class ChatClient {
|
|
|
82
100
|
this.ws = ws;
|
|
83
101
|
const onError = () => reject(new Error('websocket failed to open'));
|
|
84
102
|
ws.addEventListener('open', () => {
|
|
85
|
-
this.reconnectAttempt = 0;
|
|
86
103
|
this.emit('connected');
|
|
87
104
|
resolve();
|
|
88
105
|
}, { once: true });
|
|
@@ -105,7 +122,9 @@ class ChatClient {
|
|
|
105
122
|
this.emit('closed', 'ended');
|
|
106
123
|
return;
|
|
107
124
|
}
|
|
108
|
-
|
|
125
|
+
// Before a first join the app is still waiting on connect(), which
|
|
126
|
+
// reports the failure; there is no session to restore.
|
|
127
|
+
if (!this.closedByUs && this.joinedOnce)
|
|
109
128
|
void this.scheduleReconnect();
|
|
110
129
|
});
|
|
111
130
|
});
|
package/dist/cjs/chat.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../../src/chat.ts"],"names":[],"mappings":";;;AA+EA,2EAA2E;AAC3E,MAAa,YAAa,SAAQ,KAAK;IAChB;IAArB,YAAqB,IAAY,EAAE,OAAe;QAChD,KAAK,CAAC,GAAG,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC;QADV,SAAI,GAAJ,IAAI,CAAQ;QAE/B,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC7B,CAAC;CACF;AALD,oCAKC;AAUD,MAAM,cAAc,GAAG,MAAM,CAAC;AAC9B,MAAM,sBAAsB,GAAG,CAAC,CAAC;AACjC,mFAAmF;AACnF,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,WAAW;IACX,UAAU;IACV,wEAAwE;IACxE,iBAAiB;IACjB,qBAAqB;IACrB,uBAAuB;IACvB,kBAAkB;CACnB,CAAC,CAAC;AAEH,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AAEpE;;;GAGG;AACH,MAAa,UAAU;
|
|
1
|
+
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../../src/chat.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What kind of device is publishing, and which video codec it should send.
|
|
3
|
+
*
|
|
4
|
+
* Phones and tablets get different defaults from computers: each simulcast
|
|
5
|
+
* layer is a separate encode, and a phone encoding VP8 does it in software.
|
|
6
|
+
* Under that load Chrome shrinks the picture, and with three layers asked for
|
|
7
|
+
* it then sends only two and drops the TOP one: viewers got 180×320 from a
|
|
8
|
+
* 720p phone. Two layers in hardware H.264 keep the full picture.
|
|
9
|
+
*
|
|
10
|
+
* Everything here reads the browser through small injectable parameters, so
|
|
11
|
+
* tests can stand in for any device.
|
|
12
|
+
*/
|
|
13
|
+
import type { types as ms } from 'mediasoup-client';
|
|
14
|
+
type RtpCodecCapability = ms.RtpCodecCapability;
|
|
15
|
+
/** What the SDK reads about the browser to choose its defaults. */
|
|
16
|
+
export interface DeviceEnv {
|
|
17
|
+
userAgent: string;
|
|
18
|
+
/** `navigator.userAgentData.mobile`, where the browser has it (Chromium). */
|
|
19
|
+
uaMobile?: boolean;
|
|
20
|
+
maxTouchPoints: number;
|
|
21
|
+
}
|
|
22
|
+
/** The browser this runs in; an empty desktop-like one outside a browser. */
|
|
23
|
+
export declare function currentEnv(): DeviceEnv;
|
|
24
|
+
/**
|
|
25
|
+
* A phone or a tablet. `userAgentData.mobile` is false on Android tablets, so
|
|
26
|
+
* the user agent is checked as well.
|
|
27
|
+
*/
|
|
28
|
+
export declare function isPhoneOrTablet(env?: DeviceEnv): boolean;
|
|
29
|
+
/** An iPhone, iPad or iPod: every one of them encodes H.264 in hardware. */
|
|
30
|
+
export declare function isAppleMobile(env?: DeviceEnv): boolean;
|
|
31
|
+
/** Two layers on phones and tablets, three elsewhere. */
|
|
32
|
+
export declare function defaultLayerCount(env?: DeviceEnv): 2 | 3;
|
|
33
|
+
/** `navigator.mediaCapabilities.encodingInfo`, or a stand-in for tests. */
|
|
34
|
+
export type EncodingInfoProbe = (configuration: MediaEncodingConfiguration) => Promise<MediaCapabilitiesEncodingInfo>;
|
|
35
|
+
/** The browser's own probe, when it has one. */
|
|
36
|
+
export declare function currentProbe(): EncodingInfoProbe | undefined;
|
|
37
|
+
/** The H.264 the media server takes: constrained baseline, packetization mode 1. */
|
|
38
|
+
export declare const H264_CONTENT_TYPE = "video/H264;profile-level-id=42e01f;packetization-mode=1";
|
|
39
|
+
/**
|
|
40
|
+
* Whether this browser encodes H.264 at this size and bitrate in hardware:
|
|
41
|
+
* true or false when it says so, null when it cannot say (no
|
|
42
|
+
* `mediaCapabilities`, no `webrtc` support in it, an error, or no answer in
|
|
43
|
+
* time). Publishing never waits on it for more than a moment.
|
|
44
|
+
*/
|
|
45
|
+
export declare function h264HardwareEncode(video: {
|
|
46
|
+
width: number;
|
|
47
|
+
height: number;
|
|
48
|
+
bitrate: number;
|
|
49
|
+
}, probe?: EncodingInfoProbe | undefined, timeoutMs?: number): Promise<boolean | null>;
|
|
50
|
+
/** What `PublishOptions.codec` may say. */
|
|
51
|
+
export type CodecPreference = 'auto' | 'vp8' | 'h264';
|
|
52
|
+
/** 'vp8' or 'h264' in any case; anything else, including nothing, is 'auto'. */
|
|
53
|
+
export declare function normalizeCodec(codec: unknown): CodecPreference;
|
|
54
|
+
export interface CodecChoiceInput {
|
|
55
|
+
requested: CodecPreference;
|
|
56
|
+
phoneOrTablet: boolean;
|
|
57
|
+
appleMobile: boolean;
|
|
58
|
+
/** This browser can send H.264 to this server (it is in the device's send capabilities). */
|
|
59
|
+
h264Available: boolean;
|
|
60
|
+
/** What the hardware probe said; null when it could not say. Only asked for 'auto' on phones and tablets. */
|
|
61
|
+
h264Hardware: boolean | null;
|
|
62
|
+
}
|
|
63
|
+
export interface CodecChoice {
|
|
64
|
+
codec: 'vp8' | 'h264';
|
|
65
|
+
/** Set when the codec asked for cannot be used: report it, and publish anyway. */
|
|
66
|
+
warning?: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The codec to publish with.
|
|
70
|
+
*
|
|
71
|
+
* 'auto' is H.264 on a phone or tablet that encodes it in hardware, and VP8
|
|
72
|
+
* everywhere else: computers encode VP8 well, and a few desktop browsers
|
|
73
|
+
* cannot decode H.264. When the probe cannot say, an Apple device is taken to
|
|
74
|
+
* have hardware H.264 (they all do) and anything else is not.
|
|
75
|
+
*/
|
|
76
|
+
export declare function chooseCodec(input: CodecChoiceInput): CodecChoice;
|
|
77
|
+
/**
|
|
78
|
+
* The device's own capability entry for a codec, to hand to `produce()`.
|
|
79
|
+
* Only ever pass `produce()` an entry from the device's send capabilities:
|
|
80
|
+
* mediasoup-client adds the transceiver before it checks the codec, so one it
|
|
81
|
+
* cannot match leaves a transceiver behind that breaks every later produce.
|
|
82
|
+
*/
|
|
83
|
+
export declare function findCodec(codecs: readonly RtpCodecCapability[] | undefined, codec: 'vp8' | 'h264'): RtpCodecCapability | undefined;
|
|
84
|
+
export {};
|
|
85
|
+
//# sourceMappingURL=device.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../src/device.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,KAAK,IAAI,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAEpD,KAAK,kBAAkB,GAAG,EAAE,CAAC,kBAAkB,CAAC;AAEhD,mEAAmE;AACnE,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,6EAA6E;AAC7E,wBAAgB,UAAU,IAAI,SAAS,CAStC;AAMD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,GAAE,SAAwB,GAAG,OAAO,CAItE;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,GAAG,GAAE,SAAwB,GAAG,OAAO,CAEpE;AAED,yDAAyD;AACzD,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,SAAwB,GAAG,CAAC,GAAG,CAAC,CAEtE;AAED,2EAA2E;AAC3E,MAAM,MAAM,iBAAiB,GAAG,CAAC,aAAa,EAAE,0BAA0B,KAAK,OAAO,CAAC,6BAA6B,CAAC,CAAC;AAEtH,gDAAgD;AAChD,wBAAgB,YAAY,IAAI,iBAAiB,GAAG,SAAS,CAK5D;AAED,oFAAoF;AACpF,eAAO,MAAM,iBAAiB,4DAA4D,CAAC;AAI3F;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EACzD,KAAK,GAAE,iBAAiB,GAAG,SAA0B,EACrD,SAAS,SAAmB,GAC3B,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAyBzB;AAED,2CAA2C;AAC3C,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;AAEtD,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAG9D;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,eAAe,CAAC;IAC3B,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,4FAA4F;IAC5F,aAAa,EAAE,OAAO,CAAC;IACvB,6GAA6G;IAC7G,YAAY,EAAE,OAAO,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,KAAK,GAAG,MAAM,CAAC;IACtB,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,WAAW,CAShE;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,kBAAkB,EAAE,GAAG,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAIlI"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.H264_CONTENT_TYPE = void 0;
|
|
4
|
+
exports.currentEnv = currentEnv;
|
|
5
|
+
exports.isPhoneOrTablet = isPhoneOrTablet;
|
|
6
|
+
exports.isAppleMobile = isAppleMobile;
|
|
7
|
+
exports.defaultLayerCount = defaultLayerCount;
|
|
8
|
+
exports.currentProbe = currentProbe;
|
|
9
|
+
exports.h264HardwareEncode = h264HardwareEncode;
|
|
10
|
+
exports.normalizeCodec = normalizeCodec;
|
|
11
|
+
exports.chooseCodec = chooseCodec;
|
|
12
|
+
exports.findCodec = findCodec;
|
|
13
|
+
/** The browser this runs in; an empty desktop-like one outside a browser. */
|
|
14
|
+
function currentEnv() {
|
|
15
|
+
if (typeof navigator === 'undefined')
|
|
16
|
+
return { userAgent: '', maxTouchPoints: 0 };
|
|
17
|
+
const nav = navigator;
|
|
18
|
+
const mobile = nav.userAgentData?.mobile;
|
|
19
|
+
return {
|
|
20
|
+
userAgent: typeof nav.userAgent === 'string' ? nav.userAgent : '',
|
|
21
|
+
...(typeof mobile === 'boolean' ? { uaMobile: mobile } : {}),
|
|
22
|
+
maxTouchPoints: typeof nav.maxTouchPoints === 'number' ? nav.maxTouchPoints : 0,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
// iPadOS asks for desktop sites, so an iPad says "Macintosh". No Mac has a
|
|
26
|
+
// touch screen, so one that reports touch points is an iPad.
|
|
27
|
+
const isIPadOS = (env) => /Macintosh/.test(env.userAgent) && env.maxTouchPoints > 1;
|
|
28
|
+
/**
|
|
29
|
+
* A phone or a tablet. `userAgentData.mobile` is false on Android tablets, so
|
|
30
|
+
* the user agent is checked as well.
|
|
31
|
+
*/
|
|
32
|
+
function isPhoneOrTablet(env = currentEnv()) {
|
|
33
|
+
if (env.uaMobile === true)
|
|
34
|
+
return true;
|
|
35
|
+
if (/Android|iPhone|iPad|iPod|Mobile/.test(env.userAgent))
|
|
36
|
+
return true;
|
|
37
|
+
return isIPadOS(env);
|
|
38
|
+
}
|
|
39
|
+
/** An iPhone, iPad or iPod: every one of them encodes H.264 in hardware. */
|
|
40
|
+
function isAppleMobile(env = currentEnv()) {
|
|
41
|
+
return /iPhone|iPad|iPod/.test(env.userAgent) || isIPadOS(env);
|
|
42
|
+
}
|
|
43
|
+
/** Two layers on phones and tablets, three elsewhere. */
|
|
44
|
+
function defaultLayerCount(env = currentEnv()) {
|
|
45
|
+
return isPhoneOrTablet(env) ? 2 : 3;
|
|
46
|
+
}
|
|
47
|
+
/** The browser's own probe, when it has one. */
|
|
48
|
+
function currentProbe() {
|
|
49
|
+
if (typeof navigator === 'undefined')
|
|
50
|
+
return undefined;
|
|
51
|
+
const capabilities = navigator.mediaCapabilities;
|
|
52
|
+
if (!capabilities || typeof capabilities.encodingInfo !== 'function')
|
|
53
|
+
return undefined;
|
|
54
|
+
return (configuration) => capabilities.encodingInfo(configuration);
|
|
55
|
+
}
|
|
56
|
+
/** The H.264 the media server takes: constrained baseline, packetization mode 1. */
|
|
57
|
+
exports.H264_CONTENT_TYPE = 'video/H264;profile-level-id=42e01f;packetization-mode=1';
|
|
58
|
+
const PROBE_TIMEOUT_MS = 1500;
|
|
59
|
+
/**
|
|
60
|
+
* Whether this browser encodes H.264 at this size and bitrate in hardware:
|
|
61
|
+
* true or false when it says so, null when it cannot say (no
|
|
62
|
+
* `mediaCapabilities`, no `webrtc` support in it, an error, or no answer in
|
|
63
|
+
* time). Publishing never waits on it for more than a moment.
|
|
64
|
+
*/
|
|
65
|
+
async function h264HardwareEncode(video, probe = currentProbe(), timeoutMs = PROBE_TIMEOUT_MS) {
|
|
66
|
+
if (!probe)
|
|
67
|
+
return null;
|
|
68
|
+
let timer;
|
|
69
|
+
try {
|
|
70
|
+
const answer = probe({
|
|
71
|
+
type: 'webrtc',
|
|
72
|
+
video: {
|
|
73
|
+
contentType: exports.H264_CONTENT_TYPE,
|
|
74
|
+
width: Math.round(video.width),
|
|
75
|
+
height: Math.round(video.height),
|
|
76
|
+
bitrate: video.bitrate,
|
|
77
|
+
framerate: 30,
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
const late = new Promise((resolve) => {
|
|
81
|
+
timer = setTimeout(() => resolve(null), timeoutMs);
|
|
82
|
+
});
|
|
83
|
+
const info = await Promise.race([answer, late]);
|
|
84
|
+
if (!info)
|
|
85
|
+
return null;
|
|
86
|
+
return Boolean(info.supported && info.powerEfficient);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
if (timer !== undefined)
|
|
93
|
+
clearTimeout(timer);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/** 'vp8' or 'h264' in any case; anything else, including nothing, is 'auto'. */
|
|
97
|
+
function normalizeCodec(codec) {
|
|
98
|
+
const name = typeof codec === 'string' ? codec.toLowerCase() : '';
|
|
99
|
+
return name === 'vp8' || name === 'h264' ? name : 'auto';
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The codec to publish with.
|
|
103
|
+
*
|
|
104
|
+
* 'auto' is H.264 on a phone or tablet that encodes it in hardware, and VP8
|
|
105
|
+
* everywhere else: computers encode VP8 well, and a few desktop browsers
|
|
106
|
+
* cannot decode H.264. When the probe cannot say, an Apple device is taken to
|
|
107
|
+
* have hardware H.264 (they all do) and anything else is not.
|
|
108
|
+
*/
|
|
109
|
+
function chooseCodec(input) {
|
|
110
|
+
if (input.requested === 'h264') {
|
|
111
|
+
return input.h264Available
|
|
112
|
+
? { codec: 'h264' }
|
|
113
|
+
: { codec: 'vp8', warning: 'H.264 was asked for, but this browser cannot send it to this server: publishing VP8 instead' };
|
|
114
|
+
}
|
|
115
|
+
if (input.requested === 'vp8')
|
|
116
|
+
return { codec: 'vp8' };
|
|
117
|
+
if (!input.phoneOrTablet || !input.h264Available)
|
|
118
|
+
return { codec: 'vp8' };
|
|
119
|
+
return { codec: (input.h264Hardware ?? input.appleMobile) ? 'h264' : 'vp8' };
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* The device's own capability entry for a codec, to hand to `produce()`.
|
|
123
|
+
* Only ever pass `produce()` an entry from the device's send capabilities:
|
|
124
|
+
* mediasoup-client adds the transceiver before it checks the codec, so one it
|
|
125
|
+
* cannot match leaves a transceiver behind that breaks every later produce.
|
|
126
|
+
*/
|
|
127
|
+
function findCodec(codecs, codec) {
|
|
128
|
+
if (!codecs)
|
|
129
|
+
return undefined;
|
|
130
|
+
if (codec === 'vp8')
|
|
131
|
+
return codecs.find((c) => c.mimeType.toLowerCase() === 'video/vp8');
|
|
132
|
+
return codecs.find((c) => c.mimeType.toLowerCase() === 'video/h264' && Number(c.parameters?.['packetization-mode'] ?? 0) === 1);
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=device.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device.js","sourceRoot":"","sources":["../../src/device.ts"],"names":[],"mappings":"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"}
|