livekit-client 0.18.4 → 1.0.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/README.md +1 -1
- package/dist/api/SignalClient.d.ts +2 -2
- package/dist/api/SignalClient.d.ts.map +1 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/livekit-client.esm.mjs +263 -261
- package/dist/livekit-client.esm.mjs.map +1 -1
- package/dist/livekit-client.umd.js +1 -1
- package/dist/livekit-client.umd.js.map +1 -1
- package/dist/options.d.ts +1 -68
- package/dist/options.d.ts.map +1 -1
- package/dist/room/DeviceManager.d.ts.map +1 -1
- package/dist/room/RTCEngine.d.ts +3 -2
- package/dist/room/RTCEngine.d.ts.map +1 -1
- package/dist/room/Room.d.ts +11 -7
- package/dist/room/Room.d.ts.map +1 -1
- package/dist/room/events.d.ts +6 -12
- package/dist/room/events.d.ts.map +1 -1
- package/dist/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/room/participant/Participant.d.ts +0 -4
- package/dist/room/participant/Participant.d.ts.map +1 -1
- package/dist/room/participant/RemoteParticipant.d.ts +3 -2
- package/dist/room/participant/RemoteParticipant.d.ts.map +1 -1
- package/dist/room/participant/publishUtils.d.ts.map +1 -1
- package/dist/room/track/RemoteVideoTrack.d.ts +2 -0
- package/dist/room/track/RemoteVideoTrack.d.ts.map +1 -1
- package/dist/room/track/Track.d.ts +7 -3
- package/dist/room/track/Track.d.ts.map +1 -1
- package/dist/room/track/defaults.d.ts.map +1 -1
- package/dist/room/track/options.d.ts +9 -30
- package/dist/room/track/options.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/api/SignalClient.ts +32 -7
- package/src/index.ts +2 -2
- package/src/options.ts +0 -82
- package/src/room/DeviceManager.ts +4 -1
- package/src/room/RTCEngine.ts +16 -7
- package/src/room/Room.ts +65 -41
- package/src/room/events.ts +7 -14
- package/src/room/participant/LocalParticipant.ts +37 -9
- package/src/room/participant/Participant.ts +0 -5
- package/src/room/participant/RemoteParticipant.ts +16 -5
- package/src/room/participant/publishUtils.test.ts +2 -2
- package/src/room/participant/publishUtils.ts +34 -5
- package/src/room/track/LocalAudioTrack.ts +2 -2
- package/src/room/track/LocalTrack.ts +17 -17
- package/src/room/track/LocalVideoTrack.ts +3 -3
- package/src/room/track/RemoteVideoTrack.ts +15 -2
- package/src/room/track/Track.ts +20 -13
- package/src/room/track/create.ts +1 -1
- package/src/room/track/defaults.ts +1 -2
- package/src/room/track/options.ts +12 -31
- package/src/room/track/utils.test.ts +6 -6
- package/src/version.ts +1 -1
- package/dist/connect.d.ts +0 -24
- package/dist/connect.d.ts.map +0 -1
- package/src/connect.ts +0 -98
@@ -75,9 +75,10 @@ export function computeVideoEncodings(
|
|
75
75
|
videoEncoding = options?.screenShareEncoding;
|
76
76
|
}
|
77
77
|
const useSimulcast = options?.simulcast;
|
78
|
+
const scalabilityMode = options?.scalabilityMode;
|
78
79
|
|
79
|
-
if ((!videoEncoding && !useSimulcast) || !width || !height) {
|
80
|
-
// when we aren't simulcasting, will need to return a single encoding without
|
80
|
+
if ((!videoEncoding && !useSimulcast && !scalabilityMode) || !width || !height) {
|
81
|
+
// when we aren't simulcasting or svc, will need to return a single encoding without
|
81
82
|
// capping bandwidth. we always require a encoding for dynacast
|
82
83
|
return [{}];
|
83
84
|
}
|
@@ -88,15 +89,43 @@ export function computeVideoEncodings(
|
|
88
89
|
log.debug('using video encoding', videoEncoding);
|
89
90
|
}
|
90
91
|
|
91
|
-
if (!useSimulcast) {
|
92
|
-
return [videoEncoding];
|
93
|
-
}
|
94
92
|
const original = new VideoPreset(
|
95
93
|
width,
|
96
94
|
height,
|
97
95
|
videoEncoding.maxBitrate,
|
98
96
|
videoEncoding.maxFramerate,
|
99
97
|
);
|
98
|
+
|
99
|
+
log.debug(`scalabilityMode ${scalabilityMode}`);
|
100
|
+
if (scalabilityMode) {
|
101
|
+
const encodings: RTCRtpEncodingParameters[] = [];
|
102
|
+
// svc use first encoding as the original, so we sort encoding from high to low
|
103
|
+
switch (scalabilityMode) {
|
104
|
+
case 'L3T3':
|
105
|
+
for (let i = 0; i < 3; i += 1) {
|
106
|
+
encodings.push({
|
107
|
+
rid: videoRids[2 - i],
|
108
|
+
scaleResolutionDownBy: 2 ** i,
|
109
|
+
maxBitrate: videoEncoding ? videoEncoding.maxBitrate / 2 ** i : 0,
|
110
|
+
/* @ts-ignore */
|
111
|
+
maxFramerate: original.encoding.maxFramerate,
|
112
|
+
/* @ts-ignore */
|
113
|
+
scalabilityMode: 'L3T3',
|
114
|
+
});
|
115
|
+
}
|
116
|
+
log.debug('encodings', encodings);
|
117
|
+
return encodings;
|
118
|
+
|
119
|
+
default:
|
120
|
+
// TODO : support other scalability modes
|
121
|
+
throw new Error(`unsupported scalabilityMode: ${scalabilityMode}`);
|
122
|
+
}
|
123
|
+
}
|
124
|
+
|
125
|
+
if (!useSimulcast) {
|
126
|
+
return [videoEncoding];
|
127
|
+
}
|
128
|
+
|
100
129
|
let presets: Array<VideoPreset> = [];
|
101
130
|
if (isScreenShare) {
|
102
131
|
presets =
|
@@ -34,7 +34,7 @@ export default class LocalAudioTrack extends LocalTrack {
|
|
34
34
|
if (this.source === Track.Source.Microphone && this.stopOnMute) {
|
35
35
|
log.debug('stopping mic track');
|
36
36
|
// also stop the track, so that microphone indicator is turned off
|
37
|
-
this.
|
37
|
+
this._mediaStreamTrack.stop();
|
38
38
|
}
|
39
39
|
await super.mute();
|
40
40
|
return this;
|
@@ -83,7 +83,7 @@ export default class LocalAudioTrack extends LocalTrack {
|
|
83
83
|
try {
|
84
84
|
stats = await this.getSenderStats();
|
85
85
|
} catch (e) {
|
86
|
-
log.error('could not get audio sender stats', e);
|
86
|
+
log.error('could not get audio sender stats', { error: e });
|
87
87
|
return;
|
88
88
|
}
|
89
89
|
|
@@ -21,14 +21,14 @@ export default class LocalTrack extends Track {
|
|
21
21
|
constraints?: MediaTrackConstraints,
|
22
22
|
) {
|
23
23
|
super(mediaTrack, kind);
|
24
|
-
this.
|
24
|
+
this._mediaStreamTrack.addEventListener('ended', this.handleEnded);
|
25
25
|
this.constraints = constraints ?? mediaTrack.getConstraints();
|
26
26
|
this.reacquireTrack = false;
|
27
27
|
this.wasMuted = false;
|
28
28
|
}
|
29
29
|
|
30
30
|
get id(): string {
|
31
|
-
return this.
|
31
|
+
return this._mediaStreamTrack.id;
|
32
32
|
}
|
33
33
|
|
34
34
|
get dimensions(): Track.Dimensions | undefined {
|
@@ -36,7 +36,7 @@ export default class LocalTrack extends Track {
|
|
36
36
|
return undefined;
|
37
37
|
}
|
38
38
|
|
39
|
-
const { width, height } = this.
|
39
|
+
const { width, height } = this._mediaStreamTrack.getSettings();
|
40
40
|
if (width && height) {
|
41
41
|
return {
|
42
42
|
width,
|
@@ -60,7 +60,7 @@ export default class LocalTrack extends Track {
|
|
60
60
|
if (this.source === Track.Source.ScreenShare) {
|
61
61
|
return;
|
62
62
|
}
|
63
|
-
const { deviceId, groupId } = this.
|
63
|
+
const { deviceId, groupId } = this._mediaStreamTrack.getSettings();
|
64
64
|
const kind = this.kind === Track.Kind.Audio ? 'audioinput' : 'videoinput';
|
65
65
|
|
66
66
|
return DeviceManager.getInstance().normalizeDeviceId(kind, deviceId, groupId);
|
@@ -83,19 +83,19 @@ export default class LocalTrack extends Track {
|
|
83
83
|
|
84
84
|
// detach
|
85
85
|
this.attachedElements.forEach((el) => {
|
86
|
-
detachTrack(this.
|
86
|
+
detachTrack(this._mediaStreamTrack, el);
|
87
87
|
});
|
88
|
-
this.
|
88
|
+
this._mediaStreamTrack.removeEventListener('ended', this.handleEnded);
|
89
89
|
// on Safari, the old audio track must be stopped before attempting to acquire
|
90
90
|
// the new track, otherwise the new track will stop with
|
91
91
|
// 'A MediaStreamTrack ended due to a capture failure`
|
92
|
-
this.
|
92
|
+
this._mediaStreamTrack.stop();
|
93
93
|
|
94
94
|
track.addEventListener('ended', this.handleEnded);
|
95
95
|
log.debug('replace MediaStreamTrack');
|
96
96
|
|
97
97
|
await this.sender.replaceTrack(track);
|
98
|
-
this.
|
98
|
+
this._mediaStreamTrack = track;
|
99
99
|
|
100
100
|
this.attachedElements.forEach((el) => {
|
101
101
|
attachToElement(track, el);
|
@@ -127,13 +127,13 @@ export default class LocalTrack extends Track {
|
|
127
127
|
|
128
128
|
// detach
|
129
129
|
this.attachedElements.forEach((el) => {
|
130
|
-
detachTrack(this.
|
130
|
+
detachTrack(this._mediaStreamTrack, el);
|
131
131
|
});
|
132
|
-
this.
|
132
|
+
this._mediaStreamTrack.removeEventListener('ended', this.handleEnded);
|
133
133
|
// on Safari, the old audio track must be stopped before attempting to acquire
|
134
134
|
// the new track, otherwise the new track will stop with
|
135
135
|
// 'A MediaStreamTrack ended due to a capture failure`
|
136
|
-
this.
|
136
|
+
this._mediaStreamTrack.stop();
|
137
137
|
|
138
138
|
// create new track and attach
|
139
139
|
const mediaStream = await navigator.mediaDevices.getUserMedia(streamConstraints);
|
@@ -142,7 +142,7 @@ export default class LocalTrack extends Track {
|
|
142
142
|
log.debug('re-acquired MediaStreamTrack');
|
143
143
|
|
144
144
|
await this.sender.replaceTrack(newTrack);
|
145
|
-
this.
|
145
|
+
this._mediaStreamTrack = newTrack;
|
146
146
|
|
147
147
|
this.attachedElements.forEach((el) => {
|
148
148
|
attachToElement(newTrack, el);
|
@@ -159,15 +159,15 @@ export default class LocalTrack extends Track {
|
|
159
159
|
}
|
160
160
|
|
161
161
|
this.isMuted = muted;
|
162
|
-
this.
|
162
|
+
this._mediaStreamTrack.enabled = !muted;
|
163
163
|
this.emit(muted ? TrackEvent.Muted : TrackEvent.Unmuted, this);
|
164
164
|
}
|
165
165
|
|
166
166
|
protected get needsReAcquisition(): boolean {
|
167
167
|
return (
|
168
|
-
this.
|
169
|
-
this.
|
170
|
-
!this.
|
168
|
+
this._mediaStreamTrack.readyState !== 'live' ||
|
169
|
+
this._mediaStreamTrack.muted ||
|
170
|
+
!this._mediaStreamTrack.enabled ||
|
171
171
|
this.reacquireTrack
|
172
172
|
);
|
173
173
|
}
|
@@ -224,6 +224,6 @@ export default class LocalTrack extends Track {
|
|
224
224
|
this._isUpstreamPaused = false;
|
225
225
|
this.emit(TrackEvent.UpstreamResumed, this);
|
226
226
|
|
227
|
-
await this.sender.replaceTrack(this.
|
227
|
+
await this.sender.replaceTrack(this._mediaStreamTrack);
|
228
228
|
}
|
229
229
|
}
|
@@ -44,7 +44,7 @@ export default class LocalVideoTrack extends LocalTrack {
|
|
44
44
|
|
45
45
|
stop() {
|
46
46
|
this.sender = undefined;
|
47
|
-
this.
|
47
|
+
this._mediaStreamTrack.getConstraints();
|
48
48
|
super.stop();
|
49
49
|
}
|
50
50
|
|
@@ -52,7 +52,7 @@ export default class LocalVideoTrack extends LocalTrack {
|
|
52
52
|
if (this.source === Track.Source.Camera) {
|
53
53
|
log.debug('stopping camera track');
|
54
54
|
// also stop the track, so that camera indicator is turned off
|
55
|
-
this.
|
55
|
+
this._mediaStreamTrack.stop();
|
56
56
|
}
|
57
57
|
await super.mute();
|
58
58
|
return this;
|
@@ -243,7 +243,7 @@ export default class LocalVideoTrack extends LocalTrack {
|
|
243
243
|
await super.handleAppVisibilityChanged();
|
244
244
|
if (!isMobile()) return;
|
245
245
|
if (this.isInBackground && this.source === Track.Source.Camera) {
|
246
|
-
this.
|
246
|
+
this._mediaStreamTrack.enabled = false;
|
247
247
|
}
|
248
248
|
}
|
249
249
|
}
|
@@ -10,6 +10,7 @@ import {
|
|
10
10
|
import RemoteTrack from './RemoteTrack';
|
11
11
|
import { attachToElement, detachTrack, Track } from './Track';
|
12
12
|
import { AdaptiveStreamSettings } from './types';
|
13
|
+
import log from '../../logger';
|
13
14
|
|
14
15
|
const REACTION_DELAY = 100;
|
15
16
|
|
@@ -27,6 +28,8 @@ export default class RemoteVideoTrack extends RemoteTrack {
|
|
27
28
|
|
28
29
|
private lastDimensions?: Track.Dimensions;
|
29
30
|
|
31
|
+
private hasUsedAttach: boolean = false;
|
32
|
+
|
30
33
|
constructor(
|
31
34
|
mediaTrack: MediaStreamTrack,
|
32
35
|
sid: string,
|
@@ -44,6 +47,15 @@ export default class RemoteVideoTrack extends RemoteTrack {
|
|
44
47
|
return this.adaptiveStreamSettings !== undefined;
|
45
48
|
}
|
46
49
|
|
50
|
+
get mediaStreamTrack() {
|
51
|
+
if (this.isAdaptiveStream && !this.hasUsedAttach) {
|
52
|
+
log.warn(
|
53
|
+
'When using adaptiveStream, you need to use remoteVideoTrack.attach() to add the track to a HTMLVideoElement, otherwise your video tracks might never start',
|
54
|
+
);
|
55
|
+
}
|
56
|
+
return this._mediaStreamTrack;
|
57
|
+
}
|
58
|
+
|
47
59
|
/** @internal */
|
48
60
|
setMuted(muted: boolean) {
|
49
61
|
super.setMuted(muted);
|
@@ -51,9 +63,9 @@ export default class RemoteVideoTrack extends RemoteTrack {
|
|
51
63
|
this.attachedElements.forEach((element) => {
|
52
64
|
// detach or attach
|
53
65
|
if (muted) {
|
54
|
-
detachTrack(this.
|
66
|
+
detachTrack(this._mediaStreamTrack, element);
|
55
67
|
} else {
|
56
|
-
attachToElement(this.
|
68
|
+
attachToElement(this._mediaStreamTrack, element);
|
57
69
|
}
|
58
70
|
});
|
59
71
|
}
|
@@ -89,6 +101,7 @@ export default class RemoteVideoTrack extends RemoteTrack {
|
|
89
101
|
// the tab comes into focus for the first time.
|
90
102
|
this.debouncedHandleResize();
|
91
103
|
}
|
104
|
+
this.hasUsedAttach = true;
|
92
105
|
return element;
|
93
106
|
}
|
94
107
|
|
package/src/room/track/Track.ts
CHANGED
@@ -12,29 +12,32 @@ 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
|
-
|
17
|
-
mediaStreamTrack: MediaStreamTrack;
|
18
|
-
|
19
15
|
attachedElements: HTMLMediaElement[] = [];
|
20
16
|
|
21
17
|
isMuted: boolean = false;
|
22
18
|
|
23
19
|
source: Track.Source;
|
24
20
|
|
25
|
-
protected isInBackground: boolean;
|
26
|
-
|
27
21
|
/**
|
28
22
|
* sid is set after track is published to server, or if it's a remote track
|
29
23
|
*/
|
30
24
|
sid?: Track.SID;
|
31
25
|
|
26
|
+
/**
|
27
|
+
* @internal
|
28
|
+
*/
|
29
|
+
mediaStream?: MediaStream;
|
30
|
+
|
31
|
+
protected _mediaStreamTrack: MediaStreamTrack;
|
32
|
+
|
33
|
+
protected isInBackground: boolean;
|
34
|
+
|
32
35
|
protected _currentBitrate: number = 0;
|
33
36
|
|
34
37
|
protected constructor(mediaTrack: MediaStreamTrack, kind: Track.Kind) {
|
35
38
|
super();
|
36
39
|
this.kind = kind;
|
37
|
-
this.
|
40
|
+
this._mediaStreamTrack = mediaTrack;
|
38
41
|
this.source = Track.Source.Unknown;
|
39
42
|
if (isWeb()) {
|
40
43
|
this.isInBackground = document.visibilityState === 'hidden';
|
@@ -49,6 +52,10 @@ export class Track extends (EventEmitter as new () => TypedEventEmitter<TrackEve
|
|
49
52
|
return this._currentBitrate;
|
50
53
|
}
|
51
54
|
|
55
|
+
get mediaStreamTrack() {
|
56
|
+
return this._mediaStreamTrack;
|
57
|
+
}
|
58
|
+
|
52
59
|
/**
|
53
60
|
* creates a new HTMLAudioElement or HTMLVideoElement, attaches to it, and returns it
|
54
61
|
*/
|
@@ -87,7 +94,7 @@ export class Track extends (EventEmitter as new () => TypedEventEmitter<TrackEve
|
|
87
94
|
// even if we believe it's already attached to the element, it's possible
|
88
95
|
// the element's srcObject was set to something else out of band.
|
89
96
|
// we'll want to re-attach it in that case
|
90
|
-
attachToElement(this.
|
97
|
+
attachToElement(this._mediaStreamTrack, element);
|
91
98
|
|
92
99
|
if (element instanceof HTMLAudioElement) {
|
93
100
|
// manually play audio to detect audio playback status
|
@@ -118,7 +125,7 @@ export class Track extends (EventEmitter as new () => TypedEventEmitter<TrackEve
|
|
118
125
|
detach(element?: HTMLMediaElement): HTMLMediaElement | HTMLMediaElement[] {
|
119
126
|
// detach from a single element
|
120
127
|
if (element) {
|
121
|
-
detachTrack(this.
|
128
|
+
detachTrack(this._mediaStreamTrack, element);
|
122
129
|
const idx = this.attachedElements.indexOf(element);
|
123
130
|
if (idx >= 0) {
|
124
131
|
this.attachedElements.splice(idx, 1);
|
@@ -130,7 +137,7 @@ export class Track extends (EventEmitter as new () => TypedEventEmitter<TrackEve
|
|
130
137
|
|
131
138
|
const detached: HTMLMediaElement[] = [];
|
132
139
|
this.attachedElements.forEach((elm) => {
|
133
|
-
detachTrack(this.
|
140
|
+
detachTrack(this._mediaStreamTrack, elm);
|
134
141
|
detached.push(elm);
|
135
142
|
this.recycleElement(elm);
|
136
143
|
this.emit(TrackEvent.ElementDetached, elm);
|
@@ -142,18 +149,18 @@ export class Track extends (EventEmitter as new () => TypedEventEmitter<TrackEve
|
|
142
149
|
}
|
143
150
|
|
144
151
|
stop() {
|
145
|
-
this.
|
152
|
+
this._mediaStreamTrack.stop();
|
146
153
|
if (isWeb()) {
|
147
154
|
document.removeEventListener('visibilitychange', this.appVisibilityChangedListener);
|
148
155
|
}
|
149
156
|
}
|
150
157
|
|
151
158
|
protected enable() {
|
152
|
-
this.
|
159
|
+
this._mediaStreamTrack.enabled = true;
|
153
160
|
}
|
154
161
|
|
155
162
|
protected disable() {
|
156
|
-
this.
|
163
|
+
this._mediaStreamTrack.enabled = false;
|
157
164
|
}
|
158
165
|
|
159
166
|
private recycleElement(element: HTMLMediaElement) {
|
package/src/room/track/create.ts
CHANGED
@@ -89,7 +89,7 @@ export async function createLocalScreenTracks(
|
|
89
89
|
options = {};
|
90
90
|
}
|
91
91
|
if (options.resolution === undefined) {
|
92
|
-
options.resolution = VideoPresets.
|
92
|
+
options.resolution = VideoPresets.h1080.resolution;
|
93
93
|
}
|
94
94
|
|
95
95
|
let videoConstraints: MediaTrackConstraints | boolean = true;
|
@@ -17,11 +17,10 @@ export const publishDefaults: TrackPublishDefaults = {
|
|
17
17
|
|
18
18
|
export const audioDefaults: AudioCaptureOptions = {
|
19
19
|
autoGainControl: true,
|
20
|
-
channelCount: 1,
|
21
20
|
echoCancellation: true,
|
22
21
|
noiseSuppression: true,
|
23
22
|
};
|
24
23
|
|
25
24
|
export const videoDefaults: VideoCaptureOptions = {
|
26
|
-
resolution: VideoPresets.
|
25
|
+
resolution: VideoPresets.h720.resolution,
|
27
26
|
};
|
@@ -33,6 +33,12 @@ export interface TrackPublishDefaults {
|
|
33
33
|
*/
|
34
34
|
simulcast?: boolean;
|
35
35
|
|
36
|
+
/**
|
37
|
+
* scalability mode for svc codecs, defaults to 'L3T3'.
|
38
|
+
* for svc codecs, simulcast is disabled.
|
39
|
+
*/
|
40
|
+
scalabilityMode?: ScalabilityMode;
|
41
|
+
|
36
42
|
/**
|
37
43
|
* custom video simulcast layers for camera tracks, defaults to h180, h360, h540
|
38
44
|
* You can specify up to two custom layers that will be used instead of
|
@@ -200,6 +206,11 @@ export interface AudioPreset {
|
|
200
206
|
|
201
207
|
export type VideoCodec = 'vp8' | 'h264' | 'av1' | 'vp9';
|
202
208
|
|
209
|
+
/**
|
210
|
+
* scalability modes for svc, only supprot l3t3 now.
|
211
|
+
*/
|
212
|
+
export type ScalabilityMode = 'L3T3';
|
213
|
+
|
203
214
|
export namespace AudioPresets {
|
204
215
|
export const telephone: AudioPreset = {
|
205
216
|
maxBitrate: 12_000,
|
@@ -221,20 +232,10 @@ export const VideoPresets = {
|
|
221
232
|
h216: new VideoPreset(384, 216, 180_000, 15),
|
222
233
|
h360: new VideoPreset(640, 360, 300_000, 20),
|
223
234
|
h540: new VideoPreset(960, 540, 600_000, 25),
|
224
|
-
h720: new VideoPreset(1280, 720,
|
235
|
+
h720: new VideoPreset(1280, 720, 1_700_000, 30),
|
225
236
|
h1080: new VideoPreset(1920, 1080, 3_000_000, 30),
|
226
237
|
h1440: new VideoPreset(2560, 1440, 5_000_000, 30),
|
227
238
|
h2160: new VideoPreset(3840, 2160, 8_000_000, 30),
|
228
|
-
/** @deprecated */
|
229
|
-
qvga: new VideoPreset(320, 180, 120_000, 10),
|
230
|
-
/** @deprecated */
|
231
|
-
vga: new VideoPreset(640, 360, 300_000, 20),
|
232
|
-
/** @deprecated */
|
233
|
-
qhd: new VideoPreset(960, 540, 600_000, 25),
|
234
|
-
/** @deprecated */
|
235
|
-
hd: new VideoPreset(1280, 720, 2_000_000, 30),
|
236
|
-
/** @deprecated */
|
237
|
-
fhd: new VideoPreset(1920, 1080, 3_000_000, 30),
|
238
239
|
} as const;
|
239
240
|
|
240
241
|
/**
|
@@ -250,16 +251,6 @@ export const VideoPresets43 = {
|
|
250
251
|
h720: new VideoPreset(960, 720, 1_500_000, 30),
|
251
252
|
h1080: new VideoPreset(1440, 1080, 2_500_000, 30),
|
252
253
|
h1440: new VideoPreset(1920, 1440, 3_500_000, 30),
|
253
|
-
/** @deprecated */
|
254
|
-
qvga: new VideoPreset(240, 180, 90_000, 10),
|
255
|
-
/** @deprecated */
|
256
|
-
vga: new VideoPreset(480, 360, 225_000, 20),
|
257
|
-
/** @deprecated */
|
258
|
-
qhd: new VideoPreset(720, 540, 450_000, 25),
|
259
|
-
/** @deprecated */
|
260
|
-
hd: new VideoPreset(960, 720, 1_500_000, 30),
|
261
|
-
/** @deprecated */
|
262
|
-
fhd: new VideoPreset(1440, 1080, 2_800_000, 30),
|
263
254
|
} as const;
|
264
255
|
|
265
256
|
export const ScreenSharePresets = {
|
@@ -268,14 +259,4 @@ export const ScreenSharePresets = {
|
|
268
259
|
h720fps15: new VideoPreset(1280, 720, 1_000_000, 15),
|
269
260
|
h1080fps15: new VideoPreset(1920, 1080, 1_500_000, 15),
|
270
261
|
h1080fps30: new VideoPreset(1920, 1080, 3_000_000, 30),
|
271
|
-
/** @deprecated */
|
272
|
-
vga: new VideoPreset(640, 360, 200_000, 3),
|
273
|
-
/** @deprecated */
|
274
|
-
hd_8: new VideoPreset(1280, 720, 400_000, 5),
|
275
|
-
/** @deprecated */
|
276
|
-
hd_15: new VideoPreset(1280, 720, 1_000_000, 15),
|
277
|
-
/** @deprecated */
|
278
|
-
fhd_15: new VideoPreset(1920, 1080, 1_500_000, 15),
|
279
|
-
/** @deprecated */
|
280
|
-
fhd_30: new VideoPreset(1920, 1080, 3_000_000, 30),
|
281
262
|
} as const;
|
@@ -8,7 +8,7 @@ describe('mergeDefaultOptions', () => {
|
|
8
8
|
};
|
9
9
|
const videoDefaults: VideoCaptureOptions = {
|
10
10
|
deviceId: 'video123',
|
11
|
-
resolution: VideoPresets.
|
11
|
+
resolution: VideoPresets.h1080.resolution,
|
12
12
|
};
|
13
13
|
|
14
14
|
it('does not enable undefined options', () => {
|
@@ -88,7 +88,7 @@ describe('constraintsForOptions', () => {
|
|
88
88
|
it('converts video options correctly', () => {
|
89
89
|
const constraints = constraintsForOptions({
|
90
90
|
video: {
|
91
|
-
resolution: VideoPresets.
|
91
|
+
resolution: VideoPresets.h720.resolution,
|
92
92
|
facingMode: 'user',
|
93
93
|
deviceId: 'video123',
|
94
94
|
},
|
@@ -102,9 +102,9 @@ describe('constraintsForOptions', () => {
|
|
102
102
|
'facingMode',
|
103
103
|
'deviceId',
|
104
104
|
]);
|
105
|
-
expect(videoOpts.width).toEqual(VideoPresets.
|
106
|
-
expect(videoOpts.height).toEqual(VideoPresets.
|
107
|
-
expect(videoOpts.frameRate).toEqual(VideoPresets.
|
108
|
-
expect(videoOpts.aspectRatio).toEqual(VideoPresets.
|
105
|
+
expect(videoOpts.width).toEqual(VideoPresets.h720.resolution.width);
|
106
|
+
expect(videoOpts.height).toEqual(VideoPresets.h720.resolution.height);
|
107
|
+
expect(videoOpts.frameRate).toEqual(VideoPresets.h720.resolution.frameRate);
|
108
|
+
expect(videoOpts.aspectRatio).toEqual(VideoPresets.h720.resolution.aspectRatio);
|
109
109
|
});
|
110
110
|
});
|
package/src/version.ts
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
export const version = '0.
|
1
|
+
export const version = '1.0.0';
|
2
2
|
export const protocolVersion = 7;
|
package/dist/connect.d.ts
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
import { ConnectOptions } from './options';
|
2
|
-
import Room from './room/Room';
|
3
|
-
export { version } from './version';
|
4
|
-
/**
|
5
|
-
* @deprecated Use room.connect() instead
|
6
|
-
*
|
7
|
-
* Connects to a LiveKit room, shorthand for `new Room()` and [[Room.connect]]
|
8
|
-
*
|
9
|
-
* ```typescript
|
10
|
-
* connect('wss://myhost.livekit.io', token, {
|
11
|
-
* // publish audio and video tracks on joining
|
12
|
-
* audio: true,
|
13
|
-
* video: true,
|
14
|
-
* captureDefaults: {
|
15
|
-
* facingMode: 'user',
|
16
|
-
* },
|
17
|
-
* })
|
18
|
-
* ```
|
19
|
-
* @param url URL to LiveKit server
|
20
|
-
* @param token AccessToken, a JWT token that includes authentication and room details
|
21
|
-
* @param options
|
22
|
-
*/
|
23
|
-
export declare function connect(url: string, token: string, options?: ConnectOptions): Promise<Room>;
|
24
|
-
//# sourceMappingURL=connect.d.ts.map
|
package/dist/connect.d.ts.map
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../src/connect.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAG3C,OAAO,IAAI,MAAM,aAAa,CAAC;AAE/B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAsEjG"}
|
package/src/connect.ts
DELETED
@@ -1,98 +0,0 @@
|
|
1
|
-
import log, { LogLevel, setLogLevel } from './logger';
|
2
|
-
import { ConnectOptions } from './options';
|
3
|
-
import { MediaDeviceFailure } from './room/errors';
|
4
|
-
import { RoomEvent } from './room/events';
|
5
|
-
import Room from './room/Room';
|
6
|
-
|
7
|
-
export { version } from './version';
|
8
|
-
|
9
|
-
/**
|
10
|
-
* @deprecated Use room.connect() instead
|
11
|
-
*
|
12
|
-
* Connects to a LiveKit room, shorthand for `new Room()` and [[Room.connect]]
|
13
|
-
*
|
14
|
-
* ```typescript
|
15
|
-
* connect('wss://myhost.livekit.io', token, {
|
16
|
-
* // publish audio and video tracks on joining
|
17
|
-
* audio: true,
|
18
|
-
* video: true,
|
19
|
-
* captureDefaults: {
|
20
|
-
* facingMode: 'user',
|
21
|
-
* },
|
22
|
-
* })
|
23
|
-
* ```
|
24
|
-
* @param url URL to LiveKit server
|
25
|
-
* @param token AccessToken, a JWT token that includes authentication and room details
|
26
|
-
* @param options
|
27
|
-
*/
|
28
|
-
export async function connect(url: string, token: string, options?: ConnectOptions): Promise<Room> {
|
29
|
-
options ??= {};
|
30
|
-
if (options.adaptiveStream === undefined) {
|
31
|
-
options.adaptiveStream = options.autoManageVideo === true ? {} : undefined;
|
32
|
-
}
|
33
|
-
setLogLevel(options.logLevel ?? LogLevel.warn);
|
34
|
-
|
35
|
-
const config: RTCConfiguration = options.rtcConfig ?? {};
|
36
|
-
if (options.iceServers) {
|
37
|
-
config.iceServers = options.iceServers;
|
38
|
-
}
|
39
|
-
|
40
|
-
const room = new Room(options);
|
41
|
-
|
42
|
-
// connect to room
|
43
|
-
await room.connect(url, token, options);
|
44
|
-
|
45
|
-
const publishAudio: boolean = options.audio ?? false;
|
46
|
-
const publishVideo: boolean = options.video ?? false;
|
47
|
-
|
48
|
-
if (publishAudio || publishVideo) {
|
49
|
-
setTimeout(async () => {
|
50
|
-
// if publishing both
|
51
|
-
let err: any;
|
52
|
-
if (publishAudio && publishVideo) {
|
53
|
-
try {
|
54
|
-
await room.localParticipant.enableCameraAndMicrophone();
|
55
|
-
} catch (e) {
|
56
|
-
const errKind = MediaDeviceFailure.getFailure(e);
|
57
|
-
log.warn('received error while creating media', { error: errKind });
|
58
|
-
if (e instanceof Error) {
|
59
|
-
log.warn(e.message);
|
60
|
-
}
|
61
|
-
|
62
|
-
// when it's a device issue, try to publish the other kind
|
63
|
-
if (
|
64
|
-
errKind === MediaDeviceFailure.NotFound ||
|
65
|
-
errKind === MediaDeviceFailure.DeviceInUse
|
66
|
-
) {
|
67
|
-
try {
|
68
|
-
await room.localParticipant.setMicrophoneEnabled(true);
|
69
|
-
} catch (audioErr) {
|
70
|
-
err = audioErr;
|
71
|
-
}
|
72
|
-
} else {
|
73
|
-
err = e;
|
74
|
-
}
|
75
|
-
}
|
76
|
-
} else if (publishAudio) {
|
77
|
-
try {
|
78
|
-
await room.localParticipant.setMicrophoneEnabled(true);
|
79
|
-
} catch (e) {
|
80
|
-
err = e;
|
81
|
-
}
|
82
|
-
} else if (publishVideo) {
|
83
|
-
try {
|
84
|
-
await room.localParticipant.setCameraEnabled(true);
|
85
|
-
} catch (e) {
|
86
|
-
err = e;
|
87
|
-
}
|
88
|
-
}
|
89
|
-
|
90
|
-
if (err) {
|
91
|
-
room.emit(RoomEvent.MediaDevicesError, err);
|
92
|
-
log.error('could not create media', err);
|
93
|
-
}
|
94
|
-
});
|
95
|
-
}
|
96
|
-
|
97
|
-
return room;
|
98
|
-
}
|