livekit-client 0.16.6 → 0.17.2
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/dist/api/RequestQueue.js +6 -6
- package/dist/api/RequestQueue.js.map +1 -1
- package/dist/api/SignalClient.d.ts +3 -1
- package/dist/api/SignalClient.js +47 -5
- package/dist/api/SignalClient.js.map +1 -1
- package/dist/connect.js +1 -1
- package/dist/connect.js.map +1 -1
- package/dist/options.d.ts +7 -2
- package/dist/proto/livekit_models.d.ts +33 -0
- package/dist/proto/livekit_models.js +213 -3
- package/dist/proto/livekit_models.js.map +1 -1
- package/dist/proto/livekit_rtc.d.ts +15 -1
- package/dist/proto/livekit_rtc.js +128 -2
- package/dist/proto/livekit_rtc.js.map +1 -1
- package/dist/room/RTCEngine.d.ts +4 -3
- package/dist/room/RTCEngine.js +34 -13
- package/dist/room/RTCEngine.js.map +1 -1
- package/dist/room/Room.js +27 -12
- package/dist/room/Room.js.map +1 -1
- package/dist/room/events.d.ts +6 -1
- package/dist/room/events.js +6 -1
- package/dist/room/events.js.map +1 -1
- package/dist/room/participant/LocalParticipant.d.ts +3 -1
- package/dist/room/participant/LocalParticipant.js +24 -1
- package/dist/room/participant/LocalParticipant.js.map +1 -1
- package/dist/room/participant/RemoteParticipant.d.ts +2 -1
- package/dist/room/participant/RemoteParticipant.js +3 -3
- package/dist/room/participant/RemoteParticipant.js.map +1 -1
- package/dist/room/participant/publishUtils.d.ts +6 -0
- package/dist/room/participant/publishUtils.js +65 -24
- package/dist/room/participant/publishUtils.js.map +1 -1
- package/dist/room/participant/publishUtils.test.js +35 -5
- package/dist/room/participant/publishUtils.test.js.map +1 -1
- package/dist/room/track/LocalAudioTrack.d.ts +2 -0
- package/dist/room/track/LocalAudioTrack.js +23 -0
- package/dist/room/track/LocalAudioTrack.js.map +1 -1
- package/dist/room/track/LocalTrack.d.ts +4 -0
- package/dist/room/track/LocalTrack.js +35 -0
- package/dist/room/track/LocalTrack.js.map +1 -1
- package/dist/room/track/LocalVideoTrack.d.ts +1 -0
- package/dist/room/track/LocalVideoTrack.js +13 -0
- package/dist/room/track/LocalVideoTrack.js.map +1 -1
- package/dist/room/track/RemoteTrack.d.ts +1 -0
- package/dist/room/track/RemoteTrack.js +2 -0
- package/dist/room/track/RemoteTrack.js.map +1 -1
- package/dist/room/track/RemoteVideoTrack.d.ts +4 -2
- package/dist/room/track/RemoteVideoTrack.js +28 -11
- package/dist/room/track/RemoteVideoTrack.js.map +1 -1
- package/dist/room/track/Track.d.ts +5 -1
- package/dist/room/track/Track.js +20 -1
- package/dist/room/track/Track.js.map +1 -1
- package/dist/room/track/create.js +1 -0
- package/dist/room/track/create.js.map +1 -1
- package/dist/room/track/defaults.js +2 -2
- package/dist/room/track/defaults.js.map +1 -1
- package/dist/room/track/options.d.ts +65 -15
- package/dist/room/track/options.js +38 -0
- package/dist/room/track/options.js.map +1 -1
- package/dist/room/track/types.d.ts +11 -0
- package/dist/room/track/utils.d.ts +10 -0
- package/dist/room/track/utils.js +46 -1
- package/dist/room/track/utils.js.map +1 -1
- package/dist/room/utils.d.ts +2 -0
- package/dist/room/utils.js +9 -1
- package/dist/room/utils.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
- package/src/api/RequestQueue.ts +7 -7
- package/src/api/SignalClient.ts +36 -6
- package/src/connect.ts +1 -1
- package/src/options.ts +12 -3
- package/src/proto/livekit_models.ts +249 -0
- package/src/proto/livekit_rtc.ts +155 -0
- package/src/room/RTCEngine.ts +39 -16
- package/src/room/Room.ts +27 -13
- package/src/room/events.ts +6 -1
- package/src/room/participant/LocalParticipant.ts +31 -4
- package/src/room/participant/RemoteParticipant.ts +4 -4
- package/src/room/participant/publishUtils.test.ts +46 -6
- package/src/room/participant/publishUtils.ts +72 -27
- package/src/room/track/LocalAudioTrack.ts +19 -1
- package/src/room/track/LocalTrack.ts +37 -0
- package/src/room/track/LocalVideoTrack.ts +9 -1
- package/src/room/track/RemoteTrack.ts +3 -0
- package/src/room/track/RemoteVideoTrack.ts +25 -10
- package/src/room/track/Track.ts +16 -2
- package/src/room/track/create.ts +1 -0
- package/src/room/track/defaults.ts +2 -2
- package/src/room/track/options.ts +55 -3
- package/src/room/track/types.ts +12 -0
- package/src/room/track/utils.ts +39 -0
- package/src/room/utils.ts +8 -0
- package/src/version.ts +1 -1
@@ -1,9 +1,10 @@
|
|
1
1
|
import log from '../../logger';
|
2
|
+
import { TrackEvent } from '../events';
|
2
3
|
import { AudioSenderStats, computeBitrate, monitorFrequency } from '../stats';
|
3
4
|
import LocalTrack from './LocalTrack';
|
4
5
|
import { AudioCaptureOptions } from './options';
|
5
6
|
import { Track } from './Track';
|
6
|
-
import { constraintsForOptions } from './utils';
|
7
|
+
import { constraintsForOptions, detectSilence } from './utils';
|
7
8
|
|
8
9
|
export default class LocalAudioTrack extends LocalTrack {
|
9
10
|
sender?: RTCRtpSender;
|
@@ -18,6 +19,7 @@ export default class LocalAudioTrack extends LocalTrack {
|
|
18
19
|
constraints?: MediaTrackConstraints,
|
19
20
|
) {
|
20
21
|
super(mediaTrack, Track.Kind.Audio, constraints);
|
22
|
+
this.checkForSilence();
|
21
23
|
}
|
22
24
|
|
23
25
|
async setDeviceId(deviceId: string) {
|
@@ -61,6 +63,12 @@ export default class LocalAudioTrack extends LocalTrack {
|
|
61
63
|
await this.restart(constraints);
|
62
64
|
}
|
63
65
|
|
66
|
+
protected async restart(constraints?: MediaTrackConstraints): Promise<LocalTrack> {
|
67
|
+
const track = await super.restart(constraints);
|
68
|
+
this.checkForSilence();
|
69
|
+
return track;
|
70
|
+
}
|
71
|
+
|
64
72
|
/* @internal */
|
65
73
|
startMonitor() {
|
66
74
|
setTimeout(() => {
|
@@ -116,4 +124,14 @@ export default class LocalAudioTrack extends LocalTrack {
|
|
116
124
|
|
117
125
|
return audioStats;
|
118
126
|
}
|
127
|
+
|
128
|
+
async checkForSilence() {
|
129
|
+
const trackIsSilent = await detectSilence(this);
|
130
|
+
if (trackIsSilent) {
|
131
|
+
if (!this.isMuted) {
|
132
|
+
log.warn('silence detected on local audio track');
|
133
|
+
}
|
134
|
+
this.emit(TrackEvent.AudioSilenceDetected);
|
135
|
+
}
|
136
|
+
}
|
119
137
|
}
|
@@ -2,6 +2,7 @@ import log from '../../logger';
|
|
2
2
|
import DeviceManager from '../DeviceManager';
|
3
3
|
import { TrackInvalidError } from '../errors';
|
4
4
|
import { TrackEvent } from '../events';
|
5
|
+
import { isMobile } from '../utils';
|
5
6
|
import { attachToElement, detachTrack, Track } from './Track';
|
6
7
|
|
7
8
|
export default class LocalTrack extends Track {
|
@@ -10,12 +11,18 @@ export default class LocalTrack extends Track {
|
|
10
11
|
|
11
12
|
protected constraints: MediaTrackConstraints;
|
12
13
|
|
14
|
+
protected wasMuted: boolean;
|
15
|
+
|
16
|
+
protected reacquireTrack: boolean;
|
17
|
+
|
13
18
|
protected constructor(
|
14
19
|
mediaTrack: MediaStreamTrack, kind: Track.Kind, constraints?: MediaTrackConstraints,
|
15
20
|
) {
|
16
21
|
super(mediaTrack, kind);
|
17
22
|
this.mediaStreamTrack.addEventListener('ended', this.handleEnded);
|
18
23
|
this.constraints = constraints ?? mediaTrack.getConstraints();
|
24
|
+
this.reacquireTrack = false;
|
25
|
+
this.wasMuted = false;
|
19
26
|
}
|
20
27
|
|
21
28
|
get id(): string {
|
@@ -104,6 +111,7 @@ export default class LocalTrack extends Track {
|
|
104
111
|
attachToElement(newTrack, el);
|
105
112
|
});
|
106
113
|
|
114
|
+
this.mediaStream = mediaStream;
|
107
115
|
this.constraints = constraints;
|
108
116
|
return this;
|
109
117
|
}
|
@@ -118,7 +126,36 @@ export default class LocalTrack extends Track {
|
|
118
126
|
this.emit(muted ? TrackEvent.Muted : TrackEvent.Unmuted, this);
|
119
127
|
}
|
120
128
|
|
129
|
+
protected get needsReAcquisition(): boolean {
|
130
|
+
return this.mediaStreamTrack.readyState !== 'live'
|
131
|
+
|| this.mediaStreamTrack.muted
|
132
|
+
|| !this.mediaStreamTrack.enabled
|
133
|
+
|| this.reacquireTrack;
|
134
|
+
}
|
135
|
+
|
136
|
+
protected async handleAppVisibilityChanged() {
|
137
|
+
await super.handleAppVisibilityChanged();
|
138
|
+
if (!isMobile()) return;
|
139
|
+
log.debug('visibility changed, is in Background: ', this.isInBackground);
|
140
|
+
|
141
|
+
if (!this.isInBackground && this.needsReAcquisition) {
|
142
|
+
log.debug('track needs to be reaquired, restarting', this.source);
|
143
|
+
await this.restart();
|
144
|
+
this.reacquireTrack = false;
|
145
|
+
// Restore muted state if had to be restarted
|
146
|
+
this.setTrackMuted(this.wasMuted);
|
147
|
+
}
|
148
|
+
|
149
|
+
// store muted state each time app goes to background
|
150
|
+
if (this.isInBackground) {
|
151
|
+
this.wasMuted = this.isMuted;
|
152
|
+
}
|
153
|
+
}
|
154
|
+
|
121
155
|
private handleEnded = () => {
|
156
|
+
if (this.isInBackground) {
|
157
|
+
this.reacquireTrack = true;
|
158
|
+
}
|
122
159
|
this.emit(TrackEvent.Ended, this);
|
123
160
|
};
|
124
161
|
}
|
@@ -3,7 +3,7 @@ import log from '../../logger';
|
|
3
3
|
import { VideoLayer, VideoQuality } from '../../proto/livekit_models';
|
4
4
|
import { SubscribedQuality } from '../../proto/livekit_rtc';
|
5
5
|
import { computeBitrate, monitorFrequency, VideoSenderStats } from '../stats';
|
6
|
-
import { isFireFox } from '../utils';
|
6
|
+
import { isFireFox, isMobile } from '../utils';
|
7
7
|
import LocalTrack from './LocalTrack';
|
8
8
|
import { VideoCaptureOptions } from './options';
|
9
9
|
import { Track } from './Track';
|
@@ -238,6 +238,14 @@ export default class LocalVideoTrack extends LocalTrack {
|
|
238
238
|
this.monitorSender();
|
239
239
|
}, monitorFrequency);
|
240
240
|
};
|
241
|
+
|
242
|
+
protected async handleAppVisibilityChanged() {
|
243
|
+
await super.handleAppVisibilityChanged();
|
244
|
+
if (!isMobile()) return;
|
245
|
+
if (this.isInBackground && this.source === Track.Source.Camera) {
|
246
|
+
this.mediaStreamTrack.enabled = false;
|
247
|
+
}
|
248
|
+
}
|
241
249
|
}
|
242
250
|
|
243
251
|
export function videoQualityForRid(rid: string): VideoQuality {
|
@@ -6,6 +6,8 @@ export default abstract class RemoteTrack extends Track {
|
|
6
6
|
/** @internal */
|
7
7
|
receiver?: RTCRtpReceiver;
|
8
8
|
|
9
|
+
streamState: Track.StreamState = Track.StreamState.Active;
|
10
|
+
|
9
11
|
constructor(
|
10
12
|
mediaTrack: MediaStreamTrack,
|
11
13
|
sid: string,
|
@@ -30,6 +32,7 @@ export default abstract class RemoteTrack extends Track {
|
|
30
32
|
// this is needed to determine when the track is finished
|
31
33
|
// we send each track down in its own MediaStream, so we can assume the
|
32
34
|
// current track is the only one that can be removed.
|
35
|
+
this.mediaStream = stream;
|
33
36
|
stream.onremovetrack = () => {
|
34
37
|
this.receiver = undefined;
|
35
38
|
this._currentBitrate = 0;
|
@@ -1,9 +1,12 @@
|
|
1
1
|
import { debounce } from 'ts-debounce';
|
2
2
|
import { TrackEvent } from '../events';
|
3
3
|
import { computeBitrate, monitorFrequency, VideoReceiverStats } from '../stats';
|
4
|
-
import {
|
4
|
+
import {
|
5
|
+
getIntersectionObserver, getResizeObserver, isMobile, ObservableMediaElement,
|
6
|
+
} from '../utils';
|
5
7
|
import RemoteTrack from './RemoteTrack';
|
6
8
|
import { attachToElement, detachTrack, Track } from './Track';
|
9
|
+
import { AdaptiveStreamSettings } from './types';
|
7
10
|
|
8
11
|
const REACTION_DELAY = 100;
|
9
12
|
|
@@ -15,7 +18,7 @@ export default class RemoteVideoTrack extends RemoteTrack {
|
|
15
18
|
|
16
19
|
private elementInfos: ElementInfo[] = [];
|
17
20
|
|
18
|
-
private
|
21
|
+
private adaptiveStreamSettings?: AdaptiveStreamSettings;
|
19
22
|
|
20
23
|
private lastVisible?: boolean;
|
21
24
|
|
@@ -25,14 +28,14 @@ export default class RemoteVideoTrack extends RemoteTrack {
|
|
25
28
|
mediaTrack: MediaStreamTrack,
|
26
29
|
sid: string,
|
27
30
|
receiver?: RTCRtpReceiver,
|
28
|
-
|
31
|
+
adaptiveStreamSettings?: AdaptiveStreamSettings,
|
29
32
|
) {
|
30
33
|
super(mediaTrack, sid, Track.Kind.Video, receiver);
|
31
|
-
this.
|
34
|
+
this.adaptiveStreamSettings = adaptiveStreamSettings;
|
32
35
|
}
|
33
36
|
|
34
37
|
get isAdaptiveStream(): boolean {
|
35
|
-
return this.
|
38
|
+
return this.adaptiveStreamSettings !== undefined;
|
36
39
|
}
|
37
40
|
|
38
41
|
/** @internal */
|
@@ -60,7 +63,7 @@ export default class RemoteVideoTrack extends RemoteTrack {
|
|
60
63
|
|
61
64
|
// It's possible attach is called multiple times on an element. When that's
|
62
65
|
// the case, we'd want to avoid adding duplicate elementInfos
|
63
|
-
if (this.
|
66
|
+
if (this.adaptiveStreamSettings
|
64
67
|
&& this.elementInfos.find((info) => info.element === element) === undefined
|
65
68
|
) {
|
66
69
|
this.elementInfos.push({
|
@@ -164,6 +167,14 @@ export default class RemoteVideoTrack extends RemoteTrack {
|
|
164
167
|
this.updateVisibility();
|
165
168
|
};
|
166
169
|
|
170
|
+
protected async handleAppVisibilityChanged() {
|
171
|
+
await super.handleAppVisibilityChanged();
|
172
|
+
if (!this.isAdaptiveStream) return;
|
173
|
+
// on desktop don't pause when tab is backgrounded
|
174
|
+
if (!isMobile()) return;
|
175
|
+
this.updateVisibility();
|
176
|
+
}
|
177
|
+
|
167
178
|
private readonly debouncedHandleResize = debounce(() => {
|
168
179
|
this.updateDimensions();
|
169
180
|
}, REACTION_DELAY);
|
@@ -173,7 +184,7 @@ export default class RemoteVideoTrack extends RemoteTrack {
|
|
173
184
|
(prev, info) => Math.max(prev, info.visibilityChangedAt || 0),
|
174
185
|
0,
|
175
186
|
);
|
176
|
-
const isVisible = this.elementInfos.some((info) => info.visible);
|
187
|
+
const isVisible = this.elementInfos.some((info) => info.visible) && !this.isInBackground;
|
177
188
|
|
178
189
|
if (this.lastVisible === isVisible) {
|
179
190
|
return;
|
@@ -195,9 +206,13 @@ export default class RemoteVideoTrack extends RemoteTrack {
|
|
195
206
|
let maxWidth = 0;
|
196
207
|
let maxHeight = 0;
|
197
208
|
for (const info of this.elementInfos) {
|
198
|
-
|
199
|
-
|
200
|
-
|
209
|
+
const pixelDensity = this.adaptiveStreamSettings?.pixelDensity ?? 1;
|
210
|
+
const pixelDensityValue = pixelDensity === 'screen' ? window.devicePixelRatio : pixelDensity;
|
211
|
+
const currentElementWidth = info.element.clientWidth * pixelDensityValue;
|
212
|
+
const currentElementHeight = info.element.clientHeight * pixelDensityValue;
|
213
|
+
if (currentElementWidth + currentElementHeight > maxWidth + maxHeight) {
|
214
|
+
maxWidth = currentElementWidth;
|
215
|
+
maxHeight = currentElementHeight;
|
201
216
|
}
|
202
217
|
}
|
203
218
|
|
package/src/room/track/Track.ts
CHANGED
@@ -12,16 +12,18 @@ const recycledElements: Array<HTMLAudioElement> = [];
|
|
12
12
|
export class Track extends (EventEmitter as new () => TypedEventEmitter<TrackEventCallbacks>) {
|
13
13
|
kind: Track.Kind;
|
14
14
|
|
15
|
+
mediaStream?: MediaStream;
|
16
|
+
|
15
17
|
mediaStreamTrack: MediaStreamTrack;
|
16
18
|
|
17
19
|
attachedElements: HTMLMediaElement[] = [];
|
18
20
|
|
19
21
|
isMuted: boolean = false;
|
20
22
|
|
21
|
-
streamState: Track.StreamState = Track.StreamState.Active;
|
22
|
-
|
23
23
|
source: Track.Source;
|
24
24
|
|
25
|
+
protected isInBackground: boolean;
|
26
|
+
|
25
27
|
/**
|
26
28
|
* sid is set after track is published to server, or if it's a remote track
|
27
29
|
*/
|
@@ -34,6 +36,8 @@ export class Track extends (EventEmitter as new () => TypedEventEmitter<TrackEve
|
|
34
36
|
this.kind = kind;
|
35
37
|
this.mediaStreamTrack = mediaTrack;
|
36
38
|
this.source = Track.Source.Unknown;
|
39
|
+
this.isInBackground = document.visibilityState === 'hidden';
|
40
|
+
document.addEventListener('visibilitychange', this.appVisibilityChangedListener);
|
37
41
|
}
|
38
42
|
|
39
43
|
/** current receive bits per second */
|
@@ -131,6 +135,7 @@ export class Track extends (EventEmitter as new () => TypedEventEmitter<TrackEve
|
|
131
135
|
|
132
136
|
stop() {
|
133
137
|
this.mediaStreamTrack.stop();
|
138
|
+
document.removeEventListener('visibilitychange', this.appVisibilityChangedListener);
|
134
139
|
}
|
135
140
|
|
136
141
|
protected enable() {
|
@@ -156,6 +161,14 @@ export class Track extends (EventEmitter as new () => TypedEventEmitter<TrackEve
|
|
156
161
|
}
|
157
162
|
}
|
158
163
|
}
|
164
|
+
|
165
|
+
appVisibilityChangedListener = () => {
|
166
|
+
this.handleAppVisibilityChanged();
|
167
|
+
};
|
168
|
+
|
169
|
+
protected async handleAppVisibilityChanged() {
|
170
|
+
this.isInBackground = document.visibilityState === 'hidden';
|
171
|
+
}
|
159
172
|
}
|
160
173
|
|
161
174
|
/** @internal */
|
@@ -318,6 +331,7 @@ export type TrackEventCallbacks = {
|
|
318
331
|
updateSubscription: () => void,
|
319
332
|
audioPlaybackStarted: () => void,
|
320
333
|
audioPlaybackFailed: (error: Error) => void,
|
334
|
+
audioSilenceDetected: () => void,
|
321
335
|
visibilityChanged: (visible: boolean, track?: any) => void,
|
322
336
|
videoDimensionsChanged: (dimensions: Track.Dimensions, track?: any) => void,
|
323
337
|
};
|
package/src/room/track/create.ts
CHANGED
@@ -7,7 +7,7 @@ export const publishDefaults: TrackPublishDefaults = {
|
|
7
7
|
audioBitrate: AudioPresets.speech.maxBitrate,
|
8
8
|
dtx: true,
|
9
9
|
simulcast: true,
|
10
|
-
screenShareEncoding: ScreenSharePresets.
|
10
|
+
screenShareEncoding: ScreenSharePresets.h1080fps15.encoding,
|
11
11
|
stopMicTrackOnMute: false,
|
12
12
|
};
|
13
13
|
|
@@ -19,5 +19,5 @@ export const audioDefaults: AudioCaptureOptions = {
|
|
19
19
|
};
|
20
20
|
|
21
21
|
export const videoDefaults: VideoCaptureOptions = {
|
22
|
-
resolution: VideoPresets.
|
22
|
+
resolution: VideoPresets.h540.resolution,
|
23
23
|
};
|
@@ -33,6 +33,20 @@ export interface TrackPublishDefaults {
|
|
33
33
|
*/
|
34
34
|
simulcast?: boolean;
|
35
35
|
|
36
|
+
/**
|
37
|
+
* custom video simulcast layers for camera tracks, defaults to h180, h360, h540
|
38
|
+
* You can specify up to two custom layers that will be used instead of
|
39
|
+
* the LiveKit default layers.
|
40
|
+
* Note: the layers need to be ordered from lowest to highest quality
|
41
|
+
*/
|
42
|
+
videoSimulcastLayers?: Array<VideoPreset>;
|
43
|
+
|
44
|
+
/**
|
45
|
+
* custom video simulcast layers for screen tracks
|
46
|
+
* Note: the layers need to be ordered from lowest to highest quality
|
47
|
+
*/
|
48
|
+
screenShareSimulcastLayers?: Array<VideoPreset>;
|
49
|
+
|
36
50
|
/**
|
37
51
|
* For local tracks, stop the underlying MediaStreamTrack when the track is muted (or paused)
|
38
52
|
* on some platforms, this option is necessary to disable the microphone recording indicator.
|
@@ -202,28 +216,66 @@ export namespace AudioPresets {
|
|
202
216
|
* Sane presets for video resolution/encoding
|
203
217
|
*/
|
204
218
|
export const VideoPresets = {
|
219
|
+
h90: new VideoPreset(160, 90, 60_000, 15),
|
220
|
+
h180: new VideoPreset(320, 180, 120_000, 15),
|
221
|
+
h216: new VideoPreset(384, 216, 180_000, 15),
|
222
|
+
h360: new VideoPreset(640, 360, 300_000, 20),
|
223
|
+
h540: new VideoPreset(960, 540, 600_000, 25),
|
224
|
+
h720: new VideoPreset(1280, 720, 2_000_000, 30),
|
225
|
+
h1080: new VideoPreset(1920, 1080, 3_000_000, 30),
|
226
|
+
h1440: new VideoPreset(2560, 1440, 5_000_000, 30),
|
227
|
+
h2160: new VideoPreset(3840, 2160, 8_000_000, 30),
|
228
|
+
/** @deprecated */
|
205
229
|
qvga: new VideoPreset(320, 180, 120_000, 10),
|
230
|
+
/** @deprecated */
|
206
231
|
vga: new VideoPreset(640, 360, 300_000, 20),
|
232
|
+
/** @deprecated */
|
207
233
|
qhd: new VideoPreset(960, 540, 600_000, 25),
|
234
|
+
/** @deprecated */
|
208
235
|
hd: new VideoPreset(1280, 720, 2_000_000, 30),
|
236
|
+
/** @deprecated */
|
209
237
|
fhd: new VideoPreset(1920, 1080, 3_000_000, 30),
|
210
|
-
};
|
238
|
+
} as const;
|
211
239
|
|
212
240
|
/**
|
213
241
|
* Four by three presets
|
214
242
|
*/
|
215
243
|
export const VideoPresets43 = {
|
244
|
+
h120: new VideoPreset(160, 120, 80_000, 15),
|
245
|
+
h180: new VideoPreset(240, 180, 100_000, 15),
|
246
|
+
h240: new VideoPreset(320, 240, 150_000, 15),
|
247
|
+
h360: new VideoPreset(480, 360, 225_000, 20),
|
248
|
+
h480: new VideoPreset(640, 480, 300_000, 20),
|
249
|
+
h540: new VideoPreset(720, 540, 450_000, 25),
|
250
|
+
h720: new VideoPreset(960, 720, 1_500_000, 30),
|
251
|
+
h1080: new VideoPreset(1440, 1080, 2_500_000, 30),
|
252
|
+
h1440: new VideoPreset(1920, 1440, 3_500_000, 30),
|
253
|
+
/** @deprecated */
|
216
254
|
qvga: new VideoPreset(240, 180, 90_000, 10),
|
255
|
+
/** @deprecated */
|
217
256
|
vga: new VideoPreset(480, 360, 225_000, 20),
|
257
|
+
/** @deprecated */
|
218
258
|
qhd: new VideoPreset(720, 540, 450_000, 25),
|
259
|
+
/** @deprecated */
|
219
260
|
hd: new VideoPreset(960, 720, 1_500_000, 30),
|
261
|
+
/** @deprecated */
|
220
262
|
fhd: new VideoPreset(1440, 1080, 2_800_000, 30),
|
221
|
-
};
|
263
|
+
} as const;
|
222
264
|
|
223
265
|
export const ScreenSharePresets = {
|
266
|
+
h360fps3: new VideoPreset(640, 360, 200_000, 3),
|
267
|
+
h720fps5: new VideoPreset(1280, 720, 400_000, 5),
|
268
|
+
h720fps15: new VideoPreset(1280, 720, 1_000_000, 15),
|
269
|
+
h1080fps15: new VideoPreset(1920, 1080, 1_500_000, 15),
|
270
|
+
h1080fps30: new VideoPreset(1920, 1080, 3_000_000, 30),
|
271
|
+
/** @deprecated */
|
224
272
|
vga: new VideoPreset(640, 360, 200_000, 3),
|
273
|
+
/** @deprecated */
|
225
274
|
hd_8: new VideoPreset(1280, 720, 400_000, 5),
|
275
|
+
/** @deprecated */
|
226
276
|
hd_15: new VideoPreset(1280, 720, 1_000_000, 15),
|
277
|
+
/** @deprecated */
|
227
278
|
fhd_15: new VideoPreset(1920, 1080, 1_500_000, 15),
|
279
|
+
/** @deprecated */
|
228
280
|
fhd_30: new VideoPreset(1920, 1080, 3_000_000, 30),
|
229
|
-
};
|
281
|
+
} as const;
|
package/src/room/track/types.ts
CHANGED
@@ -6,3 +6,15 @@ import type RemoteVideoTrack from './RemoteVideoTrack';
|
|
6
6
|
export type RemoteTrack = RemoteAudioTrack | RemoteVideoTrack;
|
7
7
|
export type AudioTrack = RemoteAudioTrack | LocalAudioTrack;
|
8
8
|
export type VideoTrack = RemoteVideoTrack | LocalVideoTrack;
|
9
|
+
|
10
|
+
export type AdaptiveStreamSettings = {
|
11
|
+
/**
|
12
|
+
* Set a custom pixel density, defaults to 1
|
13
|
+
* When streaming videos on a ultra high definition screen this setting
|
14
|
+
* let's you account for the devicePixelRatio of those screens.
|
15
|
+
* Set it to `screen` to use the actual pixel density of the screen
|
16
|
+
* Note: this might significantly increase the bandwidth consumed by people
|
17
|
+
* streaming on high definition screens.
|
18
|
+
*/
|
19
|
+
pixelDensity?: number | 'screen'
|
20
|
+
};
|
package/src/room/track/utils.ts
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
import { sleep } from '../utils';
|
1
2
|
import {
|
2
3
|
AudioCaptureOptions, CreateLocalTracksOptions,
|
3
4
|
VideoCaptureOptions,
|
4
5
|
} from './options';
|
6
|
+
import { AudioTrack } from './types';
|
5
7
|
|
6
8
|
export function mergeDefaultOptions(
|
7
9
|
options?: CreateLocalTracksOptions,
|
@@ -74,3 +76,40 @@ export function constraintsForOptions(options: CreateLocalTracksOptions): MediaS
|
|
74
76
|
}
|
75
77
|
return constraints;
|
76
78
|
}
|
79
|
+
/**
|
80
|
+
* This function detects silence on a given [[Track]] instance.
|
81
|
+
* Returns true if the track seems to be entirely silent.
|
82
|
+
*/
|
83
|
+
export async function detectSilence(
|
84
|
+
track: AudioTrack,
|
85
|
+
timeOffset = 200,
|
86
|
+
): Promise<boolean> {
|
87
|
+
const ctx = getNewAudioContext();
|
88
|
+
if (ctx) {
|
89
|
+
const analyser = ctx.createAnalyser();
|
90
|
+
analyser.fftSize = 2048;
|
91
|
+
|
92
|
+
const bufferLength = analyser.frequencyBinCount;
|
93
|
+
const dataArray = new Uint8Array(bufferLength);
|
94
|
+
const source = ctx.createMediaStreamSource(new MediaStream([track.mediaStreamTrack]));
|
95
|
+
|
96
|
+
source.connect(analyser);
|
97
|
+
await sleep(timeOffset);
|
98
|
+
analyser.getByteTimeDomainData(dataArray);
|
99
|
+
const someNoise = dataArray.some((sample) => sample !== 128 && sample !== 0);
|
100
|
+
ctx.close();
|
101
|
+
return !someNoise;
|
102
|
+
}
|
103
|
+
return false;
|
104
|
+
}
|
105
|
+
|
106
|
+
/**
|
107
|
+
* @internal
|
108
|
+
*/
|
109
|
+
export function getNewAudioContext(): AudioContext | void {
|
110
|
+
// @ts-ignore
|
111
|
+
const AudioContext = window.AudioContext || window.webkitAudioContext;
|
112
|
+
if (AudioContext) {
|
113
|
+
return new AudioContext();
|
114
|
+
}
|
115
|
+
}
|
package/src/room/utils.ts
CHANGED
@@ -23,6 +23,14 @@ export function isSafari(): boolean {
|
|
23
23
|
return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
24
24
|
}
|
25
25
|
|
26
|
+
export function isMobile(): boolean {
|
27
|
+
return /Tablet|iPad|Mobile|Android|BlackBerry/.test(navigator.userAgent);
|
28
|
+
}
|
29
|
+
|
30
|
+
export function isWeb(): boolean {
|
31
|
+
return typeof document !== 'undefined';
|
32
|
+
}
|
33
|
+
|
26
34
|
function roDispatchCallback(entries: ResizeObserverEntry[]) {
|
27
35
|
for (const entry of entries) {
|
28
36
|
(entry.target as ObservableMediaElement).handleResize(entry);
|
package/src/version.ts
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
export const version = '0.
|
1
|
+
export const version = '0.17.2';
|
2
2
|
export const protocolVersion = 6;
|