@stream-io/video-client 1.13.1 → 1.15.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 +14 -0
- package/dist/index.browser.es.js +1704 -1762
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +1706 -1780
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +1704 -1762
- package/dist/index.es.js.map +1 -1
- package/dist/src/Call.d.ts +61 -30
- package/dist/src/StreamSfuClient.d.ts +4 -5
- package/dist/src/devices/CameraManager.d.ts +5 -8
- package/dist/src/devices/InputMediaDeviceManager.d.ts +5 -5
- package/dist/src/devices/MicrophoneManager.d.ts +7 -2
- package/dist/src/devices/ScreenShareManager.d.ts +1 -2
- package/dist/src/gen/coordinator/index.d.ts +904 -515
- package/dist/src/gen/video/sfu/event/events.d.ts +38 -19
- package/dist/src/gen/video/sfu/models/models.d.ts +76 -9
- package/dist/src/helpers/array.d.ts +7 -0
- package/dist/src/permissions/PermissionsContext.d.ts +6 -0
- package/dist/src/rtc/BasePeerConnection.d.ts +90 -0
- package/dist/src/rtc/Dispatcher.d.ts +0 -1
- package/dist/src/rtc/IceTrickleBuffer.d.ts +3 -2
- package/dist/src/rtc/Publisher.d.ts +32 -86
- package/dist/src/rtc/Subscriber.d.ts +4 -56
- package/dist/src/rtc/TransceiverCache.d.ts +55 -0
- package/dist/src/rtc/codecs.d.ts +1 -15
- package/dist/src/rtc/helpers/sdp.d.ts +8 -0
- package/dist/src/rtc/helpers/tracks.d.ts +1 -0
- package/dist/src/rtc/index.d.ts +3 -0
- package/dist/src/rtc/videoLayers.d.ts +11 -25
- package/dist/src/stats/{stateStoreStatsReporter.d.ts → CallStateStatsReporter.d.ts} +5 -1
- package/dist/src/stats/SfuStatsReporter.d.ts +4 -2
- package/dist/src/stats/index.d.ts +1 -1
- package/dist/src/stats/types.d.ts +8 -0
- package/dist/src/store/CallState.d.ts +47 -5
- package/dist/src/store/rxUtils.d.ts +15 -1
- package/dist/src/types.d.ts +26 -22
- package/package.json +1 -1
- package/src/Call.ts +310 -271
- package/src/StreamSfuClient.ts +9 -14
- package/src/StreamVideoClient.ts +1 -1
- package/src/__tests__/Call.publishing.test.ts +306 -0
- package/src/devices/CameraManager.ts +33 -16
- package/src/devices/InputMediaDeviceManager.ts +36 -27
- package/src/devices/MicrophoneManager.ts +29 -8
- package/src/devices/ScreenShareManager.ts +6 -8
- package/src/devices/__tests__/CameraManager.test.ts +111 -14
- package/src/devices/__tests__/InputMediaDeviceManager.test.ts +4 -4
- package/src/devices/__tests__/MicrophoneManager.test.ts +59 -21
- package/src/devices/__tests__/ScreenShareManager.test.ts +5 -5
- package/src/devices/__tests__/mocks.ts +1 -0
- package/src/events/__tests__/internal.test.ts +132 -0
- package/src/events/__tests__/mutes.test.ts +0 -3
- package/src/events/__tests__/speaker.test.ts +92 -0
- package/src/events/participant.ts +3 -4
- package/src/gen/coordinator/index.ts +902 -514
- package/src/gen/video/sfu/event/events.ts +91 -30
- package/src/gen/video/sfu/models/models.ts +105 -13
- package/src/helpers/array.ts +14 -0
- package/src/permissions/PermissionsContext.ts +22 -0
- package/src/permissions/__tests__/PermissionsContext.test.ts +40 -0
- package/src/rpc/__tests__/createClient.test.ts +38 -0
- package/src/rpc/createClient.ts +11 -5
- package/src/rtc/BasePeerConnection.ts +240 -0
- package/src/rtc/Dispatcher.ts +0 -9
- package/src/rtc/IceTrickleBuffer.ts +24 -4
- package/src/rtc/Publisher.ts +210 -528
- package/src/rtc/Subscriber.ts +26 -200
- package/src/rtc/TransceiverCache.ts +120 -0
- package/src/rtc/__tests__/Publisher.test.ts +407 -210
- package/src/rtc/__tests__/Subscriber.test.ts +88 -36
- package/src/rtc/__tests__/mocks/webrtc.mocks.ts +22 -2
- package/src/rtc/__tests__/videoLayers.test.ts +161 -54
- package/src/rtc/codecs.ts +1 -131
- package/src/rtc/helpers/__tests__/rtcConfiguration.test.ts +34 -0
- package/src/rtc/helpers/__tests__/sdp.test.ts +59 -0
- package/src/rtc/helpers/sdp.ts +30 -0
- package/src/rtc/helpers/tracks.ts +3 -0
- package/src/rtc/index.ts +4 -0
- package/src/rtc/videoLayers.ts +68 -76
- package/src/stats/{stateStoreStatsReporter.ts → CallStateStatsReporter.ts} +58 -27
- package/src/stats/SfuStatsReporter.ts +31 -3
- package/src/stats/index.ts +1 -1
- package/src/stats/types.ts +12 -0
- package/src/store/CallState.ts +115 -5
- package/src/store/__tests__/CallState.test.ts +101 -0
- package/src/store/rxUtils.ts +23 -1
- package/src/types.ts +27 -22
- package/dist/src/helpers/sdp-munging.d.ts +0 -24
- package/dist/src/rtc/bitrateLookup.d.ts +0 -2
- package/dist/src/rtc/helpers/iceCandidate.d.ts +0 -2
- package/src/helpers/__tests__/hq-audio-sdp.ts +0 -332
- package/src/helpers/__tests__/sdp-munging.test.ts +0 -283
- package/src/helpers/sdp-munging.ts +0 -265
- package/src/rtc/__tests__/bitrateLookup.test.ts +0 -12
- package/src/rtc/__tests__/codecs.test.ts +0 -145
- package/src/rtc/bitrateLookup.ts +0 -61
- package/src/rtc/helpers/iceCandidate.ts +0 -16
- /package/dist/src/{compatibility.d.ts → helpers/compatibility.d.ts} +0 -0
- /package/src/{compatibility.ts → helpers/compatibility.ts} +0 -0
package/src/rtc/Subscriber.ts
CHANGED
|
@@ -1,22 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
BasePeerConnection,
|
|
3
|
+
BasePeerConnectionOpts,
|
|
4
|
+
} from './BasePeerConnection';
|
|
3
5
|
import { PeerType } from '../gen/video/sfu/models/models';
|
|
4
6
|
import { SubscriberOffer } from '../gen/video/sfu/event/events';
|
|
5
|
-
import { Dispatcher } from './Dispatcher';
|
|
6
|
-
import { getLogger } from '../logger';
|
|
7
|
-
import { CallingState, CallState } from '../store';
|
|
8
|
-
import { withoutConcurrency } from '../helpers/concurrency';
|
|
9
7
|
import { toTrackType, trackTypeToParticipantStreamKey } from './helpers/tracks';
|
|
10
|
-
import { Logger } from '../coordinator/connection/types';
|
|
11
|
-
|
|
12
|
-
export type SubscriberOpts = {
|
|
13
|
-
sfuClient: StreamSfuClient;
|
|
14
|
-
dispatcher: Dispatcher;
|
|
15
|
-
state: CallState;
|
|
16
|
-
connectionConfig?: RTCConfiguration;
|
|
17
|
-
onUnrecoverableError?: () => void;
|
|
18
|
-
logTag: string;
|
|
19
|
-
};
|
|
20
8
|
|
|
21
9
|
/**
|
|
22
10
|
* A wrapper around the `RTCPeerConnection` that handles the incoming
|
|
@@ -24,138 +12,30 @@ export type SubscriberOpts = {
|
|
|
24
12
|
*
|
|
25
13
|
* @internal
|
|
26
14
|
*/
|
|
27
|
-
export class Subscriber {
|
|
28
|
-
private readonly logger: Logger;
|
|
29
|
-
private pc: RTCPeerConnection;
|
|
30
|
-
private sfuClient: StreamSfuClient;
|
|
31
|
-
private state: CallState;
|
|
32
|
-
|
|
33
|
-
private readonly unregisterOnSubscriberOffer: () => void;
|
|
34
|
-
private readonly unregisterOnIceRestart: () => void;
|
|
35
|
-
private readonly onUnrecoverableError?: () => void;
|
|
36
|
-
|
|
37
|
-
private isIceRestarting = false;
|
|
38
|
-
|
|
15
|
+
export class Subscriber extends BasePeerConnection {
|
|
39
16
|
/**
|
|
40
17
|
* Constructs a new `Subscriber` instance.
|
|
41
|
-
*
|
|
42
|
-
* @param sfuClient the SFU client to use.
|
|
43
|
-
* @param dispatcher the dispatcher to use.
|
|
44
|
-
* @param state the state of the call.
|
|
45
|
-
* @param connectionConfig the connection configuration to use.
|
|
46
|
-
* @param iceRestartDelay the delay in milliseconds to wait before restarting ICE when connection goes to `disconnected` state.
|
|
47
|
-
* @param onUnrecoverableError a callback to call when an unrecoverable error occurs.
|
|
48
|
-
* @param logTag a tag to use for logging.
|
|
49
18
|
*/
|
|
50
|
-
constructor({
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
state,
|
|
54
|
-
connectionConfig,
|
|
55
|
-
onUnrecoverableError,
|
|
56
|
-
logTag,
|
|
57
|
-
}: SubscriberOpts) {
|
|
58
|
-
this.logger = getLogger(['Subscriber', logTag]);
|
|
59
|
-
this.sfuClient = sfuClient;
|
|
60
|
-
this.state = state;
|
|
61
|
-
this.onUnrecoverableError = onUnrecoverableError;
|
|
19
|
+
constructor(opts: BasePeerConnectionOpts) {
|
|
20
|
+
super(PeerType.SUBSCRIBER, opts);
|
|
21
|
+
this.pc.addEventListener('track', this.handleOnTrack);
|
|
62
22
|
|
|
63
|
-
this.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
this.unregisterOnSubscriberOffer = dispatcher.on(
|
|
67
|
-
'subscriberOffer',
|
|
68
|
-
(subscriberOffer) => {
|
|
69
|
-
withoutConcurrency(subscriberOfferConcurrencyTag, () => {
|
|
70
|
-
return this.negotiate(subscriberOffer);
|
|
71
|
-
}).catch((err) => {
|
|
72
|
-
this.logger('error', `Negotiation failed.`, err);
|
|
73
|
-
});
|
|
74
|
-
},
|
|
75
|
-
);
|
|
76
|
-
|
|
77
|
-
const iceRestartConcurrencyTag = Symbol('iceRestart');
|
|
78
|
-
this.unregisterOnIceRestart = dispatcher.on('iceRestart', (iceRestart) => {
|
|
79
|
-
withoutConcurrency(iceRestartConcurrencyTag, async () => {
|
|
80
|
-
if (iceRestart.peerType !== PeerType.SUBSCRIBER) return;
|
|
81
|
-
await this.restartIce();
|
|
82
|
-
}).catch((err) => {
|
|
83
|
-
this.logger('error', `ICERestart failed`, err);
|
|
84
|
-
this.onUnrecoverableError?.();
|
|
23
|
+
this.on('subscriberOffer', async (subscriberOffer) => {
|
|
24
|
+
return this.negotiate(subscriberOffer).catch((err) => {
|
|
25
|
+
this.logger('error', `Negotiation failed.`, err);
|
|
85
26
|
});
|
|
86
27
|
});
|
|
87
28
|
}
|
|
88
29
|
|
|
89
|
-
/**
|
|
90
|
-
* Creates a new `RTCPeerConnection` instance with the given configuration.
|
|
91
|
-
*
|
|
92
|
-
* @param connectionConfig the connection configuration to use.
|
|
93
|
-
*/
|
|
94
|
-
private createPeerConnection = (connectionConfig?: RTCConfiguration) => {
|
|
95
|
-
const pc = new RTCPeerConnection(connectionConfig);
|
|
96
|
-
pc.addEventListener('icecandidate', this.onIceCandidate);
|
|
97
|
-
pc.addEventListener('track', this.handleOnTrack);
|
|
98
|
-
|
|
99
|
-
pc.addEventListener('icecandidateerror', this.onIceCandidateError);
|
|
100
|
-
pc.addEventListener(
|
|
101
|
-
'iceconnectionstatechange',
|
|
102
|
-
this.onIceConnectionStateChange,
|
|
103
|
-
);
|
|
104
|
-
pc.addEventListener(
|
|
105
|
-
'icegatheringstatechange',
|
|
106
|
-
this.onIceGatheringStateChange,
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
return pc;
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Closes the `RTCPeerConnection` and unsubscribes from the dispatcher.
|
|
114
|
-
*/
|
|
115
|
-
close = () => {
|
|
116
|
-
this.detachEventHandlers();
|
|
117
|
-
this.pc.close();
|
|
118
|
-
};
|
|
119
|
-
|
|
120
30
|
/**
|
|
121
31
|
* Detaches the event handlers from the `RTCPeerConnection`.
|
|
122
32
|
* This is useful when we want to replace the `RTCPeerConnection`
|
|
123
33
|
* instance with a new one (in case of migration).
|
|
124
34
|
*/
|
|
125
|
-
detachEventHandlers
|
|
126
|
-
|
|
127
|
-
this.unregisterOnIceRestart();
|
|
128
|
-
|
|
129
|
-
this.pc.removeEventListener('icecandidate', this.onIceCandidate);
|
|
35
|
+
detachEventHandlers() {
|
|
36
|
+
super.detachEventHandlers();
|
|
130
37
|
this.pc.removeEventListener('track', this.handleOnTrack);
|
|
131
|
-
|
|
132
|
-
this.pc.removeEventListener(
|
|
133
|
-
'iceconnectionstatechange',
|
|
134
|
-
this.onIceConnectionStateChange,
|
|
135
|
-
);
|
|
136
|
-
this.pc.removeEventListener(
|
|
137
|
-
'icegatheringstatechange',
|
|
138
|
-
this.onIceGatheringStateChange,
|
|
139
|
-
);
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Returns the result of the `RTCPeerConnection.getStats()` method
|
|
144
|
-
* @param selector
|
|
145
|
-
* @returns
|
|
146
|
-
*/
|
|
147
|
-
getStats = (selector?: MediaStreamTrack | null | undefined) => {
|
|
148
|
-
return this.pc.getStats(selector);
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Sets the SFU client to use.
|
|
153
|
-
*
|
|
154
|
-
* @param sfuClient the SFU client to use.
|
|
155
|
-
*/
|
|
156
|
-
setSfuClient = (sfuClient: StreamSfuClient) => {
|
|
157
|
-
this.sfuClient = sfuClient;
|
|
158
|
-
};
|
|
38
|
+
}
|
|
159
39
|
|
|
160
40
|
/**
|
|
161
41
|
* Restarts the ICE connection and renegotiates with the SFU.
|
|
@@ -239,7 +119,18 @@ export class Subscriber {
|
|
|
239
119
|
this.logger('error', `Unknown track type: ${rawTrackType}`);
|
|
240
120
|
return;
|
|
241
121
|
}
|
|
122
|
+
|
|
123
|
+
// get the previous stream to dispose it later
|
|
124
|
+
// usually this happens during migration, when the stream is replaced
|
|
125
|
+
// with a new one but the old one is still in the state
|
|
242
126
|
const previousStream = participantToUpdate[streamKindProp];
|
|
127
|
+
|
|
128
|
+
// replace the previous stream with the new one, prevents flickering
|
|
129
|
+
this.state.updateParticipant(participantToUpdate.sessionId, {
|
|
130
|
+
[streamKindProp]: primaryStream,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// now, dispose the previous stream if it exists
|
|
243
134
|
if (previousStream) {
|
|
244
135
|
this.logger(
|
|
245
136
|
'info',
|
|
@@ -250,26 +141,6 @@ export class Subscriber {
|
|
|
250
141
|
previousStream.removeTrack(t);
|
|
251
142
|
});
|
|
252
143
|
}
|
|
253
|
-
this.state.updateParticipant(participantToUpdate.sessionId, {
|
|
254
|
-
[streamKindProp]: primaryStream,
|
|
255
|
-
});
|
|
256
|
-
};
|
|
257
|
-
|
|
258
|
-
private onIceCandidate = (e: RTCPeerConnectionIceEvent) => {
|
|
259
|
-
const { candidate } = e;
|
|
260
|
-
if (!candidate) {
|
|
261
|
-
this.logger('debug', 'null ice candidate');
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
this.sfuClient
|
|
266
|
-
.iceTrickle({
|
|
267
|
-
iceCandidate: getIceCandidate(candidate),
|
|
268
|
-
peerType: PeerType.SUBSCRIBER,
|
|
269
|
-
})
|
|
270
|
-
.catch((err) => {
|
|
271
|
-
this.logger('warn', `ICETrickle failed`, err);
|
|
272
|
-
});
|
|
273
144
|
};
|
|
274
145
|
|
|
275
146
|
private negotiate = async (subscriberOffer: SubscriberOffer) => {
|
|
@@ -280,16 +151,7 @@ export class Subscriber {
|
|
|
280
151
|
sdp: subscriberOffer.sdp,
|
|
281
152
|
});
|
|
282
153
|
|
|
283
|
-
this.
|
|
284
|
-
async (candidate) => {
|
|
285
|
-
try {
|
|
286
|
-
const iceCandidate = JSON.parse(candidate.iceCandidate);
|
|
287
|
-
await this.pc.addIceCandidate(iceCandidate);
|
|
288
|
-
} catch (e) {
|
|
289
|
-
this.logger('warn', `ICE candidate error`, [e, candidate]);
|
|
290
|
-
}
|
|
291
|
-
},
|
|
292
|
-
);
|
|
154
|
+
this.addTrickledIceCandidates();
|
|
293
155
|
|
|
294
156
|
const answer = await this.pc.createAnswer();
|
|
295
157
|
await this.pc.setLocalDescription(answer);
|
|
@@ -301,40 +163,4 @@ export class Subscriber {
|
|
|
301
163
|
|
|
302
164
|
this.isIceRestarting = false;
|
|
303
165
|
};
|
|
304
|
-
|
|
305
|
-
private onIceConnectionStateChange = () => {
|
|
306
|
-
const state = this.pc.iceConnectionState;
|
|
307
|
-
this.logger('debug', `ICE connection state changed`, state);
|
|
308
|
-
|
|
309
|
-
if (this.state.callingState === CallingState.RECONNECTING) return;
|
|
310
|
-
|
|
311
|
-
// do nothing when ICE is restarting
|
|
312
|
-
if (this.isIceRestarting) return;
|
|
313
|
-
|
|
314
|
-
if (state === 'failed' || state === 'disconnected') {
|
|
315
|
-
this.logger('debug', `Attempting to restart ICE`);
|
|
316
|
-
this.restartIce().catch((e) => {
|
|
317
|
-
this.logger('error', `ICE restart failed`, e);
|
|
318
|
-
this.onUnrecoverableError?.();
|
|
319
|
-
});
|
|
320
|
-
}
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
private onIceGatheringStateChange = () => {
|
|
324
|
-
this.logger(
|
|
325
|
-
'debug',
|
|
326
|
-
`ICE gathering state changed`,
|
|
327
|
-
this.pc.iceGatheringState,
|
|
328
|
-
);
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
private onIceCandidateError = (e: Event) => {
|
|
332
|
-
const errorMessage =
|
|
333
|
-
e instanceof RTCPeerConnectionIceErrorEvent &&
|
|
334
|
-
`${e.errorCode}: ${e.errorText}`;
|
|
335
|
-
const iceState = this.pc.iceConnectionState;
|
|
336
|
-
const logLevel =
|
|
337
|
-
iceState === 'connected' || iceState === 'checking' ? 'debug' : 'warn';
|
|
338
|
-
this.logger(logLevel, `ICE Candidate error`, errorMessage);
|
|
339
|
-
};
|
|
340
166
|
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { PublishOption, TrackType } from '../gen/video/sfu/models/models';
|
|
2
|
+
import { OptimalVideoLayer } from './videoLayers';
|
|
3
|
+
|
|
4
|
+
type TransceiverId = {
|
|
5
|
+
publishOption: PublishOption;
|
|
6
|
+
transceiver: RTCRtpTransceiver;
|
|
7
|
+
};
|
|
8
|
+
type TrackLayersCache = {
|
|
9
|
+
publishOption: PublishOption;
|
|
10
|
+
layers: OptimalVideoLayer[];
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export class TransceiverCache {
|
|
14
|
+
private readonly cache: TransceiverId[] = [];
|
|
15
|
+
private readonly layers: TrackLayersCache[] = [];
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* An array maintaining the order how transceivers were added to the peer connection.
|
|
19
|
+
* This is needed because some browsers (Firefox) don't reliably report
|
|
20
|
+
* trackId and `mid` parameters.
|
|
21
|
+
*/
|
|
22
|
+
private readonly transceiverOrder: RTCRtpTransceiver[] = [];
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Adds a transceiver to the cache.
|
|
26
|
+
*/
|
|
27
|
+
add = (publishOption: PublishOption, transceiver: RTCRtpTransceiver) => {
|
|
28
|
+
this.cache.push({ publishOption, transceiver });
|
|
29
|
+
this.transceiverOrder.push(transceiver);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Gets the transceiver for the given publish option.
|
|
34
|
+
*/
|
|
35
|
+
get = (publishOption: PublishOption): RTCRtpTransceiver | undefined => {
|
|
36
|
+
return this.findTransceiver(publishOption)?.transceiver;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Gets the last transceiver for the given track type and publish option id.
|
|
41
|
+
*/
|
|
42
|
+
getWith = (trackType: TrackType, id: number) => {
|
|
43
|
+
return this.findTransceiver({ trackType, id })?.transceiver;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Checks if the cache has the given publish option.
|
|
48
|
+
*/
|
|
49
|
+
has = (publishOption: PublishOption): boolean => {
|
|
50
|
+
return !!this.get(publishOption);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Finds the first transceiver that satisfies the given predicate.
|
|
55
|
+
*/
|
|
56
|
+
find = (
|
|
57
|
+
predicate: (item: TransceiverId) => boolean,
|
|
58
|
+
): TransceiverId | undefined => {
|
|
59
|
+
return this.cache.find(predicate);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Provides all the items in the cache.
|
|
64
|
+
*/
|
|
65
|
+
items = (): TransceiverId[] => {
|
|
66
|
+
return this.cache;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Init index of the transceiver in the cache.
|
|
71
|
+
*/
|
|
72
|
+
indexOf = (transceiver: RTCRtpTransceiver): number => {
|
|
73
|
+
return this.transceiverOrder.indexOf(transceiver);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Gets cached video layers for the given track.
|
|
78
|
+
*/
|
|
79
|
+
getLayers = (
|
|
80
|
+
publishOption: PublishOption,
|
|
81
|
+
): OptimalVideoLayer[] | undefined => {
|
|
82
|
+
const entry = this.layers.find(
|
|
83
|
+
(item) =>
|
|
84
|
+
item.publishOption.id === publishOption.id &&
|
|
85
|
+
item.publishOption.trackType === publishOption.trackType,
|
|
86
|
+
);
|
|
87
|
+
return entry?.layers;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Sets the video layers for the given track.
|
|
92
|
+
*/
|
|
93
|
+
setLayers = (
|
|
94
|
+
publishOption: PublishOption,
|
|
95
|
+
layers: OptimalVideoLayer[] = [],
|
|
96
|
+
) => {
|
|
97
|
+
const entry = this.findLayer(publishOption);
|
|
98
|
+
if (entry) {
|
|
99
|
+
entry.layers = layers;
|
|
100
|
+
} else {
|
|
101
|
+
this.layers.push({ publishOption, layers });
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
private findTransceiver = (publishOption: Partial<PublishOption>) => {
|
|
106
|
+
return this.cache.find(
|
|
107
|
+
(item) =>
|
|
108
|
+
item.publishOption.id === publishOption.id &&
|
|
109
|
+
item.publishOption.trackType === publishOption.trackType,
|
|
110
|
+
);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
private findLayer = (publishOption: PublishOption) => {
|
|
114
|
+
return this.layers.find(
|
|
115
|
+
(item) =>
|
|
116
|
+
item.publishOption.id === publishOption.id &&
|
|
117
|
+
item.publishOption.trackType === publishOption.trackType,
|
|
118
|
+
);
|
|
119
|
+
};
|
|
120
|
+
}
|