livekit-client 2.10.0 → 2.11.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/dist/livekit-client.esm.mjs +248 -103
- 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/src/room/RTCEngine.d.ts +1 -0
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/StreamWriter.d.ts +1 -1
- package/dist/src/room/StreamWriter.d.ts.map +1 -1
- package/dist/src/room/events.d.ts +2 -1
- package/dist/src/room/events.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts +10 -1
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/track/create.d.ts.map +1 -1
- package/dist/ts4.2/src/room/RTCEngine.d.ts +1 -0
- package/dist/ts4.2/src/room/StreamWriter.d.ts +1 -1
- package/dist/ts4.2/src/room/events.d.ts +2 -1
- package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +10 -1
- package/package.json +1 -1
- package/src/api/utils.test.ts +12 -0
- package/src/api/utils.ts +4 -7
- package/src/room/DeviceManager.ts +1 -1
- package/src/room/RTCEngine.ts +5 -0
- package/src/room/Room.ts +1 -1
- package/src/room/StreamWriter.ts +1 -1
- package/src/room/defaults.ts +2 -2
- package/src/room/events.ts +1 -0
- package/src/room/participant/LocalParticipant.ts +146 -48
- package/src/room/track/create.ts +87 -47
- package/src/room/track/utils.ts +6 -6
package/src/room/track/create.ts
CHANGED
@@ -31,70 +31,110 @@ export async function createLocalTracks(
|
|
31
31
|
options?: CreateLocalTracksOptions,
|
32
32
|
): Promise<Array<LocalTrack>> {
|
33
33
|
// set default options to true
|
34
|
-
options
|
35
|
-
|
36
|
-
|
34
|
+
const internalOptions = { ...(options ?? {}) };
|
35
|
+
let attemptExactMatch = false;
|
36
|
+
let retryAudioOptions: AudioCaptureOptions | undefined | boolean = options?.audio;
|
37
|
+
let retryVideoOptions: VideoCaptureOptions | undefined | boolean = options?.video;
|
38
|
+
// if the user passes a device id as a string, we default to exact match
|
39
|
+
if (
|
40
|
+
internalOptions.audio &&
|
41
|
+
typeof internalOptions.audio === 'object' &&
|
42
|
+
typeof internalOptions.audio.deviceId === 'string'
|
43
|
+
) {
|
44
|
+
const deviceId: string = internalOptions.audio.deviceId;
|
45
|
+
internalOptions.audio.deviceId = { exact: deviceId };
|
46
|
+
attemptExactMatch = true;
|
47
|
+
retryAudioOptions = {
|
48
|
+
...internalOptions.audio,
|
49
|
+
deviceId: { ideal: deviceId },
|
50
|
+
};
|
51
|
+
}
|
52
|
+
if (
|
53
|
+
internalOptions.video &&
|
54
|
+
typeof internalOptions.video === 'object' &&
|
55
|
+
typeof internalOptions.video.deviceId === 'string'
|
56
|
+
) {
|
57
|
+
const deviceId: string = internalOptions.video.deviceId;
|
58
|
+
internalOptions.video.deviceId = { exact: deviceId };
|
59
|
+
attemptExactMatch = true;
|
60
|
+
retryVideoOptions = {
|
61
|
+
...internalOptions.video,
|
62
|
+
deviceId: { ideal: deviceId },
|
63
|
+
};
|
64
|
+
}
|
65
|
+
internalOptions.audio ??= { deviceId: 'default' };
|
66
|
+
internalOptions.video ??= { deviceId: 'default' };
|
37
67
|
|
38
|
-
const { audioProcessor, videoProcessor } = extractProcessorsFromOptions(
|
39
|
-
const opts = mergeDefaultOptions(
|
68
|
+
const { audioProcessor, videoProcessor } = extractProcessorsFromOptions(internalOptions);
|
69
|
+
const opts = mergeDefaultOptions(internalOptions, audioDefaults, videoDefaults);
|
40
70
|
const constraints = constraintsForOptions(opts);
|
41
71
|
|
42
72
|
// Keep a reference to the promise on DeviceManager and await it in getLocalDevices()
|
43
73
|
// works around iOS Safari Bug https://bugs.webkit.org/show_bug.cgi?id=179363
|
44
74
|
const mediaPromise = navigator.mediaDevices.getUserMedia(constraints);
|
45
75
|
|
46
|
-
if (
|
76
|
+
if (internalOptions.audio) {
|
47
77
|
DeviceManager.userMediaPromiseMap.set('audioinput', mediaPromise);
|
48
78
|
mediaPromise.catch(() => DeviceManager.userMediaPromiseMap.delete('audioinput'));
|
49
79
|
}
|
50
|
-
if (
|
80
|
+
if (internalOptions.video) {
|
51
81
|
DeviceManager.userMediaPromiseMap.set('videoinput', mediaPromise);
|
52
82
|
mediaPromise.catch(() => DeviceManager.userMediaPromiseMap.delete('videoinput'));
|
53
83
|
}
|
84
|
+
try {
|
85
|
+
const stream = await mediaPromise;
|
86
|
+
return await Promise.all(
|
87
|
+
stream.getTracks().map(async (mediaStreamTrack) => {
|
88
|
+
const isAudio = mediaStreamTrack.kind === 'audio';
|
89
|
+
let trackOptions = isAudio ? opts!.audio : opts!.video;
|
90
|
+
if (typeof trackOptions === 'boolean' || !trackOptions) {
|
91
|
+
trackOptions = {};
|
92
|
+
}
|
93
|
+
let trackConstraints: MediaTrackConstraints | undefined;
|
94
|
+
const conOrBool = isAudio ? constraints.audio : constraints.video;
|
95
|
+
if (typeof conOrBool !== 'boolean') {
|
96
|
+
trackConstraints = conOrBool;
|
97
|
+
}
|
54
98
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
trackConstraints = conOrBool;
|
67
|
-
}
|
99
|
+
// update the constraints with the device id the user gave permissions to in the permission prompt
|
100
|
+
// otherwise each track restart (e.g. mute - unmute) will try to initialize the device again -> causing additional permission prompts
|
101
|
+
const newDeviceId = mediaStreamTrack.getSettings().deviceId;
|
102
|
+
if (
|
103
|
+
trackConstraints?.deviceId &&
|
104
|
+
unwrapConstraint(trackConstraints.deviceId) !== newDeviceId
|
105
|
+
) {
|
106
|
+
trackConstraints.deviceId = newDeviceId;
|
107
|
+
} else if (!trackConstraints) {
|
108
|
+
trackConstraints = { deviceId: newDeviceId };
|
109
|
+
}
|
68
110
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
trackConstraints.deviceId = newDeviceId;
|
77
|
-
} else if (!trackConstraints) {
|
78
|
-
trackConstraints = { deviceId: newDeviceId };
|
79
|
-
}
|
111
|
+
const track = mediaTrackToLocalTrack(mediaStreamTrack, trackConstraints);
|
112
|
+
if (track.kind === Track.Kind.Video) {
|
113
|
+
track.source = Track.Source.Camera;
|
114
|
+
} else if (track.kind === Track.Kind.Audio) {
|
115
|
+
track.source = Track.Source.Microphone;
|
116
|
+
}
|
117
|
+
track.mediaStream = stream;
|
80
118
|
|
81
|
-
|
82
|
-
|
83
|
-
track
|
84
|
-
|
85
|
-
|
86
|
-
}
|
87
|
-
track.mediaStream = stream;
|
119
|
+
if (isAudioTrack(track) && audioProcessor) {
|
120
|
+
await track.setProcessor(audioProcessor);
|
121
|
+
} else if (isVideoTrack(track) && videoProcessor) {
|
122
|
+
await track.setProcessor(videoProcessor);
|
123
|
+
}
|
88
124
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
125
|
+
return track;
|
126
|
+
}),
|
127
|
+
);
|
128
|
+
} catch (e) {
|
129
|
+
if (!attemptExactMatch) {
|
130
|
+
throw e;
|
131
|
+
}
|
132
|
+
return createLocalTracks({
|
133
|
+
...options,
|
134
|
+
audio: retryAudioOptions,
|
135
|
+
video: retryVideoOptions,
|
136
|
+
});
|
137
|
+
}
|
98
138
|
}
|
99
139
|
|
100
140
|
/**
|
package/src/room/track/utils.ts
CHANGED
@@ -33,7 +33,7 @@ export function mergeDefaultOptions(
|
|
33
33
|
clonedOptions.audio as Record<string, unknown>,
|
34
34
|
audioDefaults as Record<string, unknown>,
|
35
35
|
);
|
36
|
-
clonedOptions.audio.deviceId ??= 'default';
|
36
|
+
clonedOptions.audio.deviceId ??= { ideal: 'default' };
|
37
37
|
if (audioProcessor || defaultAudioProcessor) {
|
38
38
|
clonedOptions.audio.processor = audioProcessor ?? defaultAudioProcessor;
|
39
39
|
}
|
@@ -43,7 +43,7 @@ export function mergeDefaultOptions(
|
|
43
43
|
clonedOptions.video as Record<string, unknown>,
|
44
44
|
videoDefaults as Record<string, unknown>,
|
45
45
|
);
|
46
|
-
clonedOptions.video.deviceId ??= 'default';
|
46
|
+
clonedOptions.video.deviceId ??= { ideal: 'default' };
|
47
47
|
if (videoProcessor || defaultVideoProcessor) {
|
48
48
|
clonedOptions.video.processor = videoProcessor ?? defaultVideoProcessor;
|
49
49
|
}
|
@@ -81,9 +81,9 @@ export function constraintsForOptions(options: CreateLocalTracksOptions): MediaS
|
|
81
81
|
}
|
82
82
|
});
|
83
83
|
constraints.video = videoOptions;
|
84
|
-
constraints.video.deviceId ??= 'default';
|
84
|
+
constraints.video.deviceId ??= { ideal: 'default' };
|
85
85
|
} else {
|
86
|
-
constraints.video = options.video ? { deviceId: 'default' } : false;
|
86
|
+
constraints.video = options.video ? { deviceId: { ideal: 'default' } } : false;
|
87
87
|
}
|
88
88
|
} else {
|
89
89
|
constraints.video = false;
|
@@ -92,9 +92,9 @@ export function constraintsForOptions(options: CreateLocalTracksOptions): MediaS
|
|
92
92
|
if (options.audio) {
|
93
93
|
if (typeof options.audio === 'object') {
|
94
94
|
constraints.audio = options.audio;
|
95
|
-
constraints.audio.deviceId ??= 'default';
|
95
|
+
constraints.audio.deviceId ??= { ideal: 'default' };
|
96
96
|
} else {
|
97
|
-
constraints.audio = { deviceId: 'default' };
|
97
|
+
constraints.audio = { deviceId: { ideal: 'default' } };
|
98
98
|
}
|
99
99
|
} else {
|
100
100
|
constraints.audio = false;
|