livekit-client 2.0.0 → 2.0.2
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +8 -0
- package/dist/livekit-client.e2ee.worker.js +1 -1
- package/dist/livekit-client.e2ee.worker.js.map +1 -1
- package/dist/livekit-client.e2ee.worker.mjs +4 -4
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +122 -39
- 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/proto/livekit_models_pb.d.ts +9 -1
- package/dist/src/proto/livekit_models_pb.d.ts.map +1 -1
- package/dist/src/proto/livekit_rtc_pb.d.ts +38 -0
- package/dist/src/proto/livekit_rtc_pb.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts +1 -2
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/PCTransportManager.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/events.d.ts +8 -1
- package/dist/src/room/events.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/track/LocalAudioTrack.d.ts +8 -7
- package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrack.d.ts +10 -9
- package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrackPublication.d.ts +2 -2
- package/dist/src/room/track/LocalVideoTrack.d.ts +3 -3
- package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/RemoteAudioTrack.d.ts +2 -1
- package/dist/src/room/track/RemoteAudioTrack.d.ts.map +1 -1
- package/dist/src/room/track/RemoteTrack.d.ts +2 -2
- package/dist/src/room/track/RemoteTrack.d.ts.map +1 -1
- package/dist/src/room/track/RemoteVideoTrack.d.ts +2 -1
- package/dist/src/room/track/RemoteVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/Track.d.ts +3 -3
- package/dist/src/room/track/Track.d.ts.map +1 -1
- package/dist/src/room/track/processor/types.d.ts +4 -0
- package/dist/src/room/track/processor/types.d.ts.map +1 -1
- package/dist/ts4.2/src/proto/livekit_models_pb.d.ts +9 -1
- package/dist/ts4.2/src/proto/livekit_rtc_pb.d.ts +38 -0
- package/dist/ts4.2/src/room/PCTransport.d.ts +1 -2
- package/dist/ts4.2/src/room/events.d.ts +8 -1
- package/dist/ts4.2/src/room/track/LocalAudioTrack.d.ts +8 -7
- package/dist/ts4.2/src/room/track/LocalTrack.d.ts +10 -9
- package/dist/ts4.2/src/room/track/LocalTrackPublication.d.ts +2 -2
- package/dist/ts4.2/src/room/track/LocalVideoTrack.d.ts +3 -3
- package/dist/ts4.2/src/room/track/RemoteAudioTrack.d.ts +2 -1
- package/dist/ts4.2/src/room/track/RemoteTrack.d.ts +2 -2
- package/dist/ts4.2/src/room/track/RemoteVideoTrack.d.ts +2 -1
- package/dist/ts4.2/src/room/track/Track.d.ts +3 -3
- package/dist/ts4.2/src/room/track/processor/types.d.ts +4 -0
- package/package.json +2 -2
- package/src/api/SignalClient.ts +1 -1
- package/src/e2ee/worker/e2ee.worker.ts +8 -4
- package/src/proto/livekit_models_pb.ts +12 -0
- package/src/proto/livekit_rtc_pb.ts +53 -0
- package/src/room/PCTransport.ts +3 -13
- package/src/room/PCTransportManager.ts +1 -2
- package/src/room/RTCEngine.ts +5 -0
- package/src/room/Room.ts +3 -0
- package/src/room/events.ts +8 -1
- package/src/room/participant/LocalParticipant.ts +0 -1
- package/src/room/track/LocalAudioTrack.ts +8 -11
- package/src/room/track/LocalTrack.ts +36 -23
- package/src/room/track/LocalVideoTrack.ts +3 -3
- package/src/room/track/RemoteAudioTrack.ts +1 -1
- package/src/room/track/RemoteTrack.ts +4 -2
- package/src/room/track/RemoteVideoTrack.ts +1 -1
- package/src/room/track/Track.ts +5 -3
- package/src/room/track/processor/types.ts +4 -0
@@ -84,7 +84,7 @@ onmessage = (ev) => {
|
|
84
84
|
}
|
85
85
|
break;
|
86
86
|
case 'removeTransform':
|
87
|
-
unsetCryptorParticipant(data.trackId);
|
87
|
+
unsetCryptorParticipant(data.trackId, data.participantIdentity);
|
88
88
|
break;
|
89
89
|
case 'updateCodec':
|
90
90
|
getTrackCryptor(data.participantIdentity, data.trackId).setVideoCodec(data.codec);
|
@@ -125,7 +125,9 @@ async function handleRatchetRequest(data: RatchetRequestMessage['data']) {
|
|
125
125
|
}
|
126
126
|
|
127
127
|
function getTrackCryptor(participantIdentity: string, trackId: string) {
|
128
|
-
let cryptor = participantCryptors.find(
|
128
|
+
let cryptor = participantCryptors.find(
|
129
|
+
(c) => c.getParticipantIdentity() === participantIdentity && c.getTrackId() === trackId,
|
130
|
+
);
|
129
131
|
if (!cryptor) {
|
130
132
|
workerLogger.info('creating new cryptor for', { participantIdentity });
|
131
133
|
if (!keyProviderOptions) {
|
@@ -172,8 +174,10 @@ function getSharedKeyHandler() {
|
|
172
174
|
return sharedKeyHandler;
|
173
175
|
}
|
174
176
|
|
175
|
-
function unsetCryptorParticipant(trackId: string) {
|
176
|
-
participantCryptors
|
177
|
+
function unsetCryptorParticipant(trackId: string, participantIdentity: string) {
|
178
|
+
participantCryptors
|
179
|
+
.find((c) => c.getParticipantIdentity() === participantIdentity && c.getTrackId() === trackId)
|
180
|
+
?.unsetParticipant();
|
177
181
|
}
|
178
182
|
|
179
183
|
function setEncryptionEnabled(enable: boolean, participantIdentity: string) {
|
@@ -301,6 +301,16 @@ export enum DisconnectReason {
|
|
301
301
|
* @generated from enum value: JOIN_FAILURE = 7;
|
302
302
|
*/
|
303
303
|
JOIN_FAILURE = 7,
|
304
|
+
|
305
|
+
/**
|
306
|
+
* @generated from enum value: MIGRATION = 8;
|
307
|
+
*/
|
308
|
+
MIGRATION = 8,
|
309
|
+
|
310
|
+
/**
|
311
|
+
* @generated from enum value: SIGNAL_CLOSE = 9;
|
312
|
+
*/
|
313
|
+
SIGNAL_CLOSE = 9,
|
304
314
|
}
|
305
315
|
// Retrieve enum metadata with: proto3.getEnumType(DisconnectReason)
|
306
316
|
proto3.util.setEnumType(DisconnectReason, "livekit.DisconnectReason", [
|
@@ -312,6 +322,8 @@ proto3.util.setEnumType(DisconnectReason, "livekit.DisconnectReason", [
|
|
312
322
|
{ no: 5, name: "ROOM_DELETED" },
|
313
323
|
{ no: 6, name: "STATE_MISMATCH" },
|
314
324
|
{ no: 7, name: "JOIN_FAILURE" },
|
325
|
+
{ no: 8, name: "MIGRATION" },
|
326
|
+
{ no: 9, name: "SIGNAL_CLOSE" },
|
315
327
|
]);
|
316
328
|
|
317
329
|
/**
|
@@ -1208,6 +1208,7 @@ export class LeaveRequest extends Message<LeaveRequest> {
|
|
1208
1208
|
/**
|
1209
1209
|
* sent when server initiates the disconnect due to server-restart
|
1210
1210
|
* indicates clients should attempt full-reconnect sequence
|
1211
|
+
* NOTE: `can_reconnect` obsoleted by `action` starting in protocol version 13
|
1211
1212
|
*
|
1212
1213
|
* @generated from field: bool can_reconnect = 1;
|
1213
1214
|
*/
|
@@ -1218,6 +1219,16 @@ export class LeaveRequest extends Message<LeaveRequest> {
|
|
1218
1219
|
*/
|
1219
1220
|
reason = DisconnectReason.UNKNOWN_REASON;
|
1220
1221
|
|
1222
|
+
/**
|
1223
|
+
* @generated from field: livekit.LeaveRequest.Action action = 3;
|
1224
|
+
*/
|
1225
|
+
action = LeaveRequest_Action.DISCONNECT;
|
1226
|
+
|
1227
|
+
/**
|
1228
|
+
* @generated from field: livekit.RegionSettings regions = 4;
|
1229
|
+
*/
|
1230
|
+
regions?: RegionSettings;
|
1231
|
+
|
1221
1232
|
constructor(data?: PartialMessage<LeaveRequest>) {
|
1222
1233
|
super();
|
1223
1234
|
proto3.util.initPartial(data, this);
|
@@ -1228,6 +1239,8 @@ export class LeaveRequest extends Message<LeaveRequest> {
|
|
1228
1239
|
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
1229
1240
|
{ no: 1, name: "can_reconnect", kind: "scalar", T: 8 /* ScalarType.BOOL */ },
|
1230
1241
|
{ no: 2, name: "reason", kind: "enum", T: proto3.getEnumType(DisconnectReason) },
|
1242
|
+
{ no: 3, name: "action", kind: "enum", T: proto3.getEnumType(LeaveRequest_Action) },
|
1243
|
+
{ no: 4, name: "regions", kind: "message", T: RegionSettings },
|
1231
1244
|
]);
|
1232
1245
|
|
1233
1246
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): LeaveRequest {
|
@@ -1247,6 +1260,40 @@ export class LeaveRequest extends Message<LeaveRequest> {
|
|
1247
1260
|
}
|
1248
1261
|
}
|
1249
1262
|
|
1263
|
+
/**
|
1264
|
+
* indicates action clients should take on receiving this message
|
1265
|
+
*
|
1266
|
+
* @generated from enum livekit.LeaveRequest.Action
|
1267
|
+
*/
|
1268
|
+
export enum LeaveRequest_Action {
|
1269
|
+
/**
|
1270
|
+
* should disconnect
|
1271
|
+
*
|
1272
|
+
* @generated from enum value: DISCONNECT = 0;
|
1273
|
+
*/
|
1274
|
+
DISCONNECT = 0,
|
1275
|
+
|
1276
|
+
/**
|
1277
|
+
* should attempt a resume with `reconnect=1` in join URL
|
1278
|
+
*
|
1279
|
+
* @generated from enum value: RESUME = 1;
|
1280
|
+
*/
|
1281
|
+
RESUME = 1,
|
1282
|
+
|
1283
|
+
/**
|
1284
|
+
* should attempt a reconnect, i. e. no `reconnect=1`
|
1285
|
+
*
|
1286
|
+
* @generated from enum value: RECONNECT = 2;
|
1287
|
+
*/
|
1288
|
+
RECONNECT = 2,
|
1289
|
+
}
|
1290
|
+
// Retrieve enum metadata with: proto3.getEnumType(LeaveRequest_Action)
|
1291
|
+
proto3.util.setEnumType(LeaveRequest_Action, "livekit.LeaveRequest.Action", [
|
1292
|
+
{ no: 0, name: "DISCONNECT" },
|
1293
|
+
{ no: 1, name: "RESUME" },
|
1294
|
+
{ no: 2, name: "RECONNECT" },
|
1295
|
+
]);
|
1296
|
+
|
1250
1297
|
/**
|
1251
1298
|
* message to indicate published video track dimensions are changing
|
1252
1299
|
*
|
@@ -1947,6 +1994,11 @@ export class SyncState extends Message<SyncState> {
|
|
1947
1994
|
*/
|
1948
1995
|
offer?: SessionDescription;
|
1949
1996
|
|
1997
|
+
/**
|
1998
|
+
* @generated from field: repeated string track_sids_disabled = 6;
|
1999
|
+
*/
|
2000
|
+
trackSidsDisabled: string[] = [];
|
2001
|
+
|
1950
2002
|
constructor(data?: PartialMessage<SyncState>) {
|
1951
2003
|
super();
|
1952
2004
|
proto3.util.initPartial(data, this);
|
@@ -1960,6 +2012,7 @@ export class SyncState extends Message<SyncState> {
|
|
1960
2012
|
{ no: 3, name: "publish_tracks", kind: "message", T: TrackPublishedResponse, repeated: true },
|
1961
2013
|
{ no: 4, name: "data_channels", kind: "message", T: DataChannelInfo, repeated: true },
|
1962
2014
|
{ no: 5, name: "offer", kind: "message", T: SessionDescription },
|
2015
|
+
{ no: 6, name: "track_sids_disabled", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true },
|
1963
2016
|
]);
|
1964
2017
|
|
1965
2018
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): SyncState {
|
package/src/room/PCTransport.ts
CHANGED
@@ -5,7 +5,7 @@ import { debounce } from 'ts-debounce';
|
|
5
5
|
import log, { LoggerNames, getLogger } from '../logger';
|
6
6
|
import { NegotiationError, UnexpectedConnectionState } from './errors';
|
7
7
|
import type { LoggerOptions } from './types';
|
8
|
-
import { ddExtensionURI,
|
8
|
+
import { ddExtensionURI, isSVCCodec } from './utils';
|
9
9
|
|
10
10
|
/** @internal */
|
11
11
|
interface TrackBitrateInfo {
|
@@ -42,8 +42,6 @@ export default class PCTransport extends EventEmitter {
|
|
42
42
|
|
43
43
|
private config?: RTCConfiguration;
|
44
44
|
|
45
|
-
private mediaConstraints: Record<string, unknown>;
|
46
|
-
|
47
45
|
private log = log;
|
48
46
|
|
49
47
|
private loggerOptions: LoggerOptions;
|
@@ -76,24 +74,16 @@ export default class PCTransport extends EventEmitter {
|
|
76
74
|
|
77
75
|
onTrack?: (ev: RTCTrackEvent) => void;
|
78
76
|
|
79
|
-
constructor(
|
80
|
-
config?: RTCConfiguration,
|
81
|
-
mediaConstraints: Record<string, unknown> = {},
|
82
|
-
loggerOptions: LoggerOptions = {},
|
83
|
-
) {
|
77
|
+
constructor(config?: RTCConfiguration, loggerOptions: LoggerOptions = {}) {
|
84
78
|
super();
|
85
79
|
this.log = getLogger(loggerOptions.loggerName ?? LoggerNames.PCTransport);
|
86
80
|
this.loggerOptions = loggerOptions;
|
87
81
|
this.config = config;
|
88
|
-
this.mediaConstraints = mediaConstraints;
|
89
82
|
this._pc = this.createPC();
|
90
83
|
}
|
91
84
|
|
92
85
|
private createPC() {
|
93
|
-
const pc =
|
94
|
-
? // @ts-expect-error chrome allows additional media constraints to be passed into the RTCPeerConnection constructor
|
95
|
-
new RTCPeerConnection(this.config, this.mediaConstraints)
|
96
|
-
: new RTCPeerConnection(this.config);
|
86
|
+
const pc = new RTCPeerConnection(this.config);
|
97
87
|
|
98
88
|
pc.onicecandidate = (ev) => {
|
99
89
|
if (!ev.candidate) return;
|
@@ -71,8 +71,7 @@ export class PCTransportManager {
|
|
71
71
|
|
72
72
|
this.isPublisherConnectionRequired = !subscriberPrimary;
|
73
73
|
this.isSubscriberConnectionRequired = subscriberPrimary;
|
74
|
-
|
75
|
-
this.publisher = new PCTransport(rtcConfig, googConstraints, loggerOptions);
|
74
|
+
this.publisher = new PCTransport(rtcConfig, loggerOptions);
|
76
75
|
this.subscriber = new PCTransport(rtcConfig, loggerOptions);
|
77
76
|
|
78
77
|
this.publisher.onConnectionStateChange = this.updateState;
|
package/src/room/RTCEngine.ts
CHANGED
@@ -1271,11 +1271,15 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
1271
1271
|
*/
|
1272
1272
|
const autoSubscribe = this.signalOpts?.autoSubscribe ?? true;
|
1273
1273
|
const trackSids = new Array<string>();
|
1274
|
+
const trackSidsDisabled = new Array<string>();
|
1274
1275
|
|
1275
1276
|
remoteTracks.forEach((track) => {
|
1276
1277
|
if (track.isDesired !== autoSubscribe) {
|
1277
1278
|
trackSids.push(track.trackSid);
|
1278
1279
|
}
|
1280
|
+
if (!track.isEnabled) {
|
1281
|
+
trackSidsDisabled.push(track.trackSid);
|
1282
|
+
}
|
1279
1283
|
});
|
1280
1284
|
|
1281
1285
|
this.client.sendSyncState(
|
@@ -1299,6 +1303,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
1299
1303
|
}),
|
1300
1304
|
publishTracks: getTrackPublicationInfo(localTracks),
|
1301
1305
|
dataChannels: this.dataChannelsInfo(),
|
1306
|
+
trackSidsDisabled,
|
1302
1307
|
}),
|
1303
1308
|
);
|
1304
1309
|
}
|
package/src/room/Room.ts
CHANGED
@@ -1776,7 +1776,10 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
|
|
1776
1776
|
};
|
1777
1777
|
|
1778
1778
|
private onLocalTrackPublished = async (pub: LocalTrackPublication) => {
|
1779
|
+
pub.track?.getProcessor()?.onPublish?.(this);
|
1780
|
+
|
1779
1781
|
this.emit(RoomEvent.LocalTrackPublished, pub, this.localParticipant);
|
1782
|
+
|
1780
1783
|
if (pub.track instanceof LocalAudioTrack) {
|
1781
1784
|
const trackIsSilent = await pub.track.checkForSilence();
|
1782
1785
|
if (trackIsSilent) {
|
package/src/room/events.ts
CHANGED
@@ -27,7 +27,14 @@ export enum RoomEvent {
|
|
27
27
|
|
28
28
|
/**
|
29
29
|
* When disconnected from room. This fires when room.disconnect() is called or
|
30
|
-
* when an unrecoverable connection issue had occured
|
30
|
+
* when an unrecoverable connection issue had occured.
|
31
|
+
*
|
32
|
+
* DisconnectReason can be used to determine why the participant was disconnected. Notable reasons are
|
33
|
+
* - DUPLICATE_IDENTITY: another client with the same identity has joined the room
|
34
|
+
* - PARTICIPANT_REMOVED: participant was removed by RemoveParticipant API
|
35
|
+
* - ROOM_DELETED: the room has ended via DeleteRoom API
|
36
|
+
*
|
37
|
+
* args: ([[DisconnectReason]])
|
31
38
|
*/
|
32
39
|
Disconnected = 'disconnected',
|
33
40
|
|
@@ -6,17 +6,17 @@ import { isWeb, unwrapConstraint } from '../utils';
|
|
6
6
|
import LocalTrack from './LocalTrack';
|
7
7
|
import { Track } from './Track';
|
8
8
|
import type { AudioCaptureOptions } from './options';
|
9
|
-
import type { TrackProcessor } from './processor/types';
|
9
|
+
import type { AudioProcessorOptions, TrackProcessor } from './processor/types';
|
10
10
|
import { constraintsForOptions, detectSilence } from './utils';
|
11
11
|
|
12
|
-
export default class LocalAudioTrack extends LocalTrack {
|
12
|
+
export default class LocalAudioTrack extends LocalTrack<Track.Kind.Audio> {
|
13
13
|
/** @internal */
|
14
14
|
stopOnMute: boolean = false;
|
15
15
|
|
16
|
-
private audioContext?: AudioContext;
|
17
|
-
|
18
16
|
private prevStats?: AudioSenderStats;
|
19
17
|
|
18
|
+
protected processor?: TrackProcessor<Track.Kind.Audio, AudioProcessorOptions> | undefined;
|
19
|
+
|
20
20
|
/**
|
21
21
|
*
|
22
22
|
* @param mediaTrack
|
@@ -48,7 +48,7 @@ export default class LocalAudioTrack extends LocalTrack {
|
|
48
48
|
);
|
49
49
|
}
|
50
50
|
|
51
|
-
async mute(): Promise<
|
51
|
+
async mute(): Promise<typeof this> {
|
52
52
|
const unlock = await this.muteLock.lock();
|
53
53
|
try {
|
54
54
|
// disabled special handling as it will cause BT headsets to switch communication modes
|
@@ -64,7 +64,7 @@ export default class LocalAudioTrack extends LocalTrack {
|
|
64
64
|
}
|
65
65
|
}
|
66
66
|
|
67
|
-
async unmute(): Promise<
|
67
|
+
async unmute(): Promise<typeof this> {
|
68
68
|
const unlock = await this.muteLock.lock();
|
69
69
|
try {
|
70
70
|
const deviceHasChanged =
|
@@ -99,7 +99,7 @@ export default class LocalAudioTrack extends LocalTrack {
|
|
99
99
|
await this.restart(constraints);
|
100
100
|
}
|
101
101
|
|
102
|
-
protected async restart(constraints?: MediaTrackConstraints): Promise<
|
102
|
+
protected async restart(constraints?: MediaTrackConstraints): Promise<typeof this> {
|
103
103
|
const track = await super.restart(constraints);
|
104
104
|
this.checkForSilence();
|
105
105
|
return track;
|
@@ -139,7 +139,7 @@ export default class LocalAudioTrack extends LocalTrack {
|
|
139
139
|
this.prevStats = stats;
|
140
140
|
};
|
141
141
|
|
142
|
-
async setProcessor(processor: TrackProcessor<
|
142
|
+
async setProcessor(processor: TrackProcessor<Track.Kind.Audio, AudioProcessorOptions>) {
|
143
143
|
const unlock = await this.processorLock.lock();
|
144
144
|
try {
|
145
145
|
if (!this.audioContext) {
|
@@ -150,9 +150,6 @@ export default class LocalAudioTrack extends LocalTrack {
|
|
150
150
|
if (this.processor) {
|
151
151
|
await this.stopProcessor();
|
152
152
|
}
|
153
|
-
if (this.kind === 'unknown') {
|
154
|
-
throw TypeError('cannot set processor on track of unknown kind');
|
155
|
-
}
|
156
153
|
|
157
154
|
const processorOptions = {
|
158
155
|
kind: this.kind,
|
@@ -11,7 +11,9 @@ import type { TrackProcessor } from './processor/types';
|
|
11
11
|
|
12
12
|
const defaultDimensionsTimeout = 1000;
|
13
13
|
|
14
|
-
export default abstract class LocalTrack
|
14
|
+
export default abstract class LocalTrack<
|
15
|
+
TrackKind extends Track.Kind = Track.Kind,
|
16
|
+
> extends Track<TrackKind> {
|
15
17
|
/** @internal */
|
16
18
|
sender?: RTCRtpSender;
|
17
19
|
|
@@ -34,10 +36,12 @@ export default abstract class LocalTrack extends Track {
|
|
34
36
|
|
35
37
|
protected processorElement?: HTMLMediaElement;
|
36
38
|
|
37
|
-
protected processor?: TrackProcessor<
|
39
|
+
protected processor?: TrackProcessor<TrackKind, any>;
|
38
40
|
|
39
41
|
protected processorLock: Mutex;
|
40
42
|
|
43
|
+
protected audioContext?: AudioContext;
|
44
|
+
|
41
45
|
/**
|
42
46
|
*
|
43
47
|
* @param mediaTrack
|
@@ -47,7 +51,7 @@ export default abstract class LocalTrack extends Track {
|
|
47
51
|
*/
|
48
52
|
protected constructor(
|
49
53
|
mediaTrack: MediaStreamTrack,
|
50
|
-
kind:
|
54
|
+
kind: TrackKind,
|
51
55
|
constraints?: MediaTrackConstraints,
|
52
56
|
userProvidedTrack = false,
|
53
57
|
loggerOptions?: LoggerOptions,
|
@@ -128,21 +132,28 @@ export default abstract class LocalTrack extends Track {
|
|
128
132
|
this._constraints = newTrack.getConstraints();
|
129
133
|
}
|
130
134
|
let processedTrack: MediaStreamTrack | undefined;
|
131
|
-
if (this.processor && newTrack
|
132
|
-
this.
|
133
|
-
|
134
|
-
|
135
|
-
|
135
|
+
if (this.processor && newTrack) {
|
136
|
+
const unlock = await this.processorLock.lock();
|
137
|
+
try {
|
138
|
+
this.log.debug('restarting processor', this.logContext);
|
139
|
+
if (this.kind === 'unknown') {
|
140
|
+
throw TypeError('cannot set processor on track of unknown kind');
|
141
|
+
}
|
136
142
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
143
|
+
if (this.processorElement) {
|
144
|
+
attachToElement(newTrack, this.processorElement);
|
145
|
+
// ensure the processorElement itself stays muted
|
146
|
+
this.processorElement.muted = true;
|
147
|
+
}
|
148
|
+
await this.processor.restart({
|
149
|
+
track: newTrack,
|
150
|
+
kind: this.kind,
|
151
|
+
element: this.processorElement,
|
152
|
+
});
|
153
|
+
processedTrack = this.processor.processedTrack;
|
154
|
+
} finally {
|
155
|
+
unlock();
|
156
|
+
}
|
146
157
|
}
|
147
158
|
if (this.sender) {
|
148
159
|
await this.sender.replaceTrack(processedTrack ?? newTrack);
|
@@ -200,17 +211,17 @@ export default abstract class LocalTrack extends Track {
|
|
200
211
|
return DeviceManager.getInstance().normalizeDeviceId(kind, deviceId, groupId);
|
201
212
|
}
|
202
213
|
|
203
|
-
async mute()
|
214
|
+
async mute() {
|
204
215
|
this.setTrackMuted(true);
|
205
216
|
return this;
|
206
217
|
}
|
207
218
|
|
208
|
-
async unmute()
|
219
|
+
async unmute() {
|
209
220
|
this.setTrackMuted(false);
|
210
221
|
return this;
|
211
222
|
}
|
212
223
|
|
213
|
-
async replaceTrack(track: MediaStreamTrack, userProvidedTrack = true)
|
224
|
+
async replaceTrack(track: MediaStreamTrack, userProvidedTrack = true) {
|
214
225
|
if (!this.sender) {
|
215
226
|
throw new TrackInvalidError('unable to replace an unpublished track');
|
216
227
|
}
|
@@ -227,7 +238,7 @@ export default abstract class LocalTrack extends Track {
|
|
227
238
|
return this;
|
228
239
|
}
|
229
240
|
|
230
|
-
protected async restart(constraints?: MediaTrackConstraints)
|
241
|
+
protected async restart(constraints?: MediaTrackConstraints) {
|
231
242
|
if (!constraints) {
|
232
243
|
constraints = this._constraints;
|
233
244
|
}
|
@@ -408,7 +419,7 @@ export default abstract class LocalTrack extends Track {
|
|
408
419
|
* @param showProcessedStreamLocally
|
409
420
|
* @returns
|
410
421
|
*/
|
411
|
-
async setProcessor(processor: TrackProcessor<
|
422
|
+
async setProcessor(processor: TrackProcessor<TrackKind>, showProcessedStreamLocally = true) {
|
412
423
|
const unlock = await this.processorLock.lock();
|
413
424
|
try {
|
414
425
|
this.log.debug('setting up processor', this.logContext);
|
@@ -418,7 +429,8 @@ export default abstract class LocalTrack extends Track {
|
|
418
429
|
if (this.kind === 'unknown') {
|
419
430
|
throw TypeError('cannot set processor on track of unknown kind');
|
420
431
|
}
|
421
|
-
this.processorElement =
|
432
|
+
this.processorElement =
|
433
|
+
this.processorElement ?? (document.createElement(this.kind) as HTMLMediaElement);
|
422
434
|
|
423
435
|
attachToElement(this._mediaStreamTrack, this.processorElement);
|
424
436
|
this.processorElement.muted = true;
|
@@ -433,6 +445,7 @@ export default abstract class LocalTrack extends Track {
|
|
433
445
|
kind: this.kind,
|
434
446
|
track: this._mediaStreamTrack,
|
435
447
|
element: this.processorElement,
|
448
|
+
audioContext: this.audioContext,
|
436
449
|
};
|
437
450
|
|
438
451
|
await processor.init(processorOptions);
|
@@ -30,7 +30,7 @@ export class SimulcastTrackInfo {
|
|
30
30
|
|
31
31
|
const refreshSubscribedCodecAfterNewCodec = 5000;
|
32
32
|
|
33
|
-
export default class LocalVideoTrack extends LocalTrack {
|
33
|
+
export default class LocalVideoTrack extends LocalTrack<Track.Kind.Video> {
|
34
34
|
/* @internal */
|
35
35
|
signalClient?: SignalClient;
|
36
36
|
|
@@ -115,7 +115,7 @@ export default class LocalVideoTrack extends LocalTrack {
|
|
115
115
|
}
|
116
116
|
}
|
117
117
|
|
118
|
-
async mute(): Promise<
|
118
|
+
async mute(): Promise<typeof this> {
|
119
119
|
const unlock = await this.muteLock.lock();
|
120
120
|
try {
|
121
121
|
if (this.source === Track.Source.Camera && !this.isUserProvided) {
|
@@ -130,7 +130,7 @@ export default class LocalVideoTrack extends LocalTrack {
|
|
130
130
|
}
|
131
131
|
}
|
132
132
|
|
133
|
-
async unmute(): Promise<
|
133
|
+
async unmute(): Promise<typeof this> {
|
134
134
|
const unlock = await this.muteLock.lock();
|
135
135
|
try {
|
136
136
|
if (this.source === Track.Source.Camera && !this.isUserProvided) {
|
@@ -7,7 +7,7 @@ import RemoteTrack from './RemoteTrack';
|
|
7
7
|
import { Track } from './Track';
|
8
8
|
import type { AudioOutputOptions } from './options';
|
9
9
|
|
10
|
-
export default class RemoteAudioTrack extends RemoteTrack {
|
10
|
+
export default class RemoteAudioTrack extends RemoteTrack<Track.Kind.Audio> {
|
11
11
|
private prevStats?: AudioReceiverStats;
|
12
12
|
|
13
13
|
private elementVolume: number | undefined;
|
@@ -3,14 +3,16 @@ import { monitorFrequency } from '../stats';
|
|
3
3
|
import type { LoggerOptions } from '../types';
|
4
4
|
import { Track } from './Track';
|
5
5
|
|
6
|
-
export default abstract class RemoteTrack
|
6
|
+
export default abstract class RemoteTrack<
|
7
|
+
TrackKind extends Track.Kind = Track.Kind,
|
8
|
+
> extends Track<TrackKind> {
|
7
9
|
/** @internal */
|
8
10
|
receiver?: RTCRtpReceiver;
|
9
11
|
|
10
12
|
constructor(
|
11
13
|
mediaTrack: MediaStreamTrack,
|
12
14
|
sid: string,
|
13
|
-
kind:
|
15
|
+
kind: TrackKind,
|
14
16
|
receiver?: RTCRtpReceiver,
|
15
17
|
loggerOptions?: LoggerOptions,
|
16
18
|
) {
|
@@ -12,7 +12,7 @@ import type { AdaptiveStreamSettings } from './types';
|
|
12
12
|
|
13
13
|
const REACTION_DELAY = 100;
|
14
14
|
|
15
|
-
export default class RemoteVideoTrack extends RemoteTrack {
|
15
|
+
export default class RemoteVideoTrack extends RemoteTrack<Track.Kind.Video> {
|
16
16
|
private prevStats?: VideoReceiverStats;
|
17
17
|
|
18
18
|
private elementInfos: ElementInfo[] = [];
|
package/src/room/track/Track.ts
CHANGED
@@ -24,8 +24,10 @@ export enum VideoQuality {
|
|
24
24
|
MEDIUM = ProtoQuality.MEDIUM,
|
25
25
|
HIGH = ProtoQuality.HIGH,
|
26
26
|
}
|
27
|
-
export abstract class Track
|
28
|
-
|
27
|
+
export abstract class Track<
|
28
|
+
TrackKind extends Track.Kind = Track.Kind,
|
29
|
+
> extends (EventEmitter as new () => TypedEventEmitter<TrackEventCallbacks>) {
|
30
|
+
readonly kind: TrackKind;
|
29
31
|
|
30
32
|
attachedElements: HTMLMediaElement[] = [];
|
31
33
|
|
@@ -67,7 +69,7 @@ export abstract class Track extends (EventEmitter as new () => TypedEventEmitter
|
|
67
69
|
|
68
70
|
protected constructor(
|
69
71
|
mediaTrack: MediaStreamTrack,
|
70
|
-
kind:
|
72
|
+
kind: TrackKind,
|
71
73
|
loggerOptions: LoggerOptions = {},
|
72
74
|
) {
|
73
75
|
super();
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import type Room from '../../Room';
|
1
2
|
import type { Track } from '../Track';
|
2
3
|
|
3
4
|
/**
|
@@ -7,6 +8,7 @@ export type ProcessorOptions<T extends Track.Kind> = {
|
|
7
8
|
kind: T;
|
8
9
|
track: MediaStreamTrack;
|
9
10
|
element?: HTMLMediaElement;
|
11
|
+
audioContext?: AudioContext;
|
10
12
|
};
|
11
13
|
|
12
14
|
/**
|
@@ -33,4 +35,6 @@ export interface TrackProcessor<
|
|
33
35
|
restart: (opts: U) => Promise<void>;
|
34
36
|
destroy: () => Promise<void>;
|
35
37
|
processedTrack?: MediaStreamTrack;
|
38
|
+
onPublish?: (room: Room) => Promise<void>;
|
39
|
+
onUnpublish?: () => Promise<void>;
|
36
40
|
}
|