@livedigital/client 3.8.0 → 3.9.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/engine/PeerConsumer.d.ts +2 -2
- package/dist/helpers/media.d.ts +2 -1
- package/dist/index.es.js +11 -11
- package/dist/index.js +11 -11
- package/dist/types/common.d.ts +1 -1
- package/package.json +1 -1
- package/src/engine/PeerConsumer.ts +28 -7
- package/src/engine/index.ts +6 -0
- package/src/engine/media/tracks/PeerTrack.ts +20 -10
- package/src/helpers/media.ts +16 -2
- package/src/types/common.ts +1 -1
package/dist/types/common.d.ts
CHANGED
|
@@ -102,7 +102,7 @@ export declare enum ConnectionQuality {
|
|
|
102
102
|
GOOD = 3
|
|
103
103
|
}
|
|
104
104
|
export declare type EncoderConfig = {};
|
|
105
|
-
export declare type VideoCodec = 'h264' | 'vp8';
|
|
105
|
+
export declare type VideoCodec = 'h264' | 'vp8' | 'vp9';
|
|
106
106
|
export declare type AudioCodec = 'opus';
|
|
107
107
|
export declare type VideoEncoderConfig = EncoderConfig & {
|
|
108
108
|
preferredCodec?: VideoCodec;
|
package/package.json
CHANGED
|
@@ -62,7 +62,7 @@ class PeerConsumer {
|
|
|
62
62
|
});
|
|
63
63
|
this.currentMaxSpatialLayer = this.appData.producerData.maxSpatialLayer;
|
|
64
64
|
this.parseScalabilityMode();
|
|
65
|
-
this.
|
|
65
|
+
this.initAvailableSpatialLayers();
|
|
66
66
|
this.setCurrentSpatialLayerParams();
|
|
67
67
|
}
|
|
68
68
|
|
|
@@ -104,26 +104,46 @@ class PeerConsumer {
|
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
|
|
108
|
-
const { encodings } = this.appData.producerData;
|
|
107
|
+
initAvailableSpatialLayers(): void {
|
|
108
|
+
const { encodings, trackTransformParams } = this.appData.producerData;
|
|
109
109
|
if (!encodings) {
|
|
110
110
|
return;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
this.availableSpatialLayers = encodings.map((encoding) => this.
|
|
113
|
+
this.availableSpatialLayers = encodings.map((encoding) => this.tryPrepareSpatialLayerParams(encoding));
|
|
114
|
+
|
|
115
|
+
if (!trackTransformParams || this.availableSpatialLayers.length > 1 || this.spatialLayers < 2) {
|
|
116
|
+
this.logger.debug('Using available spatial layers', { case: 'initAvailableSpatialLayers' });
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
this.logger.debug('Pre-generating encodings with spatial layer params', { case: 'initAvailableSpatialLayers' });
|
|
121
|
+
|
|
122
|
+
const preGeneratedEncodings: SpatialLayerParams[] = [];
|
|
123
|
+
const baseEncoding = encodings[encodings.length - 1];
|
|
124
|
+
|
|
125
|
+
// imitate encodings with spatial layers params for automatic quality switching on client side
|
|
126
|
+
for (let i = this.spatialLayers - 1; i >= 0; i -= 1) {
|
|
127
|
+
preGeneratedEncodings.push(this.tryPrepareSpatialLayerParams({
|
|
128
|
+
...baseEncoding,
|
|
129
|
+
scaleResolutionDownBy: 2 ** i,
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
this.availableSpatialLayers = preGeneratedEncodings;
|
|
114
134
|
}
|
|
115
135
|
|
|
116
136
|
setCurrentSpatialLayerParams(): void {
|
|
117
137
|
const { encodings } = this.appData.producerData;
|
|
118
|
-
if (!encodings) {
|
|
138
|
+
if (!encodings || !encodings[this.currentSpatialLayer]) {
|
|
119
139
|
return;
|
|
120
140
|
}
|
|
121
141
|
|
|
122
|
-
this.currentSpatialLayerParams = this.
|
|
142
|
+
this.currentSpatialLayerParams = this.tryPrepareSpatialLayerParams(encodings[this.currentSpatialLayer]);
|
|
123
143
|
this.logger.debug('setCurrentSpatialLayerParams()', { currentSpatialLayerParams: this.currentSpatialLayerParams });
|
|
124
144
|
}
|
|
125
145
|
|
|
126
|
-
|
|
146
|
+
tryPrepareSpatialLayerParams(encoding: RtpEncodingParameters): SpatialLayerParams {
|
|
127
147
|
const { trackTransformParams } = this.appData.producerData;
|
|
128
148
|
if (!trackTransformParams) {
|
|
129
149
|
return encoding;
|
|
@@ -131,6 +151,7 @@ class PeerConsumer {
|
|
|
131
151
|
|
|
132
152
|
const { width, height } = trackTransformParams;
|
|
133
153
|
const coefficient = encoding.scaleResolutionDownBy || 1;
|
|
154
|
+
|
|
134
155
|
if (width && height) {
|
|
135
156
|
return {
|
|
136
157
|
width: width / coefficient,
|
package/src/engine/index.ts
CHANGED
|
@@ -53,6 +53,7 @@ import {
|
|
|
53
53
|
MediaTracksFactory, AudioTrack, Track, BaseTrack,
|
|
54
54
|
} from '../types/media';
|
|
55
55
|
import ChannelStateSyncEventHandler from './handlers/ChannelStateSyncEventHandler';
|
|
56
|
+
import { getSupportedCodecsMimeTypes } from '../helpers/media';
|
|
56
57
|
|
|
57
58
|
type EngineParams = {
|
|
58
59
|
clientEventEmitter: EnhancedEventEmitter;
|
|
@@ -205,6 +206,11 @@ class Engine {
|
|
|
205
206
|
.request('router.getRtpCapabilities') as { rtpCapabilities: RtpCapabilities };
|
|
206
207
|
await this.media.createNoiseSuppressor();
|
|
207
208
|
await this.media.loadDevice(rtpCapabilities);
|
|
209
|
+
|
|
210
|
+
this.logger.info('Supported capabilities', {
|
|
211
|
+
codecs: getSupportedCodecsMimeTypes(this.media.mediasoupDevice),
|
|
212
|
+
});
|
|
213
|
+
|
|
208
214
|
this.webRtcIssueDetector?.watchNewPeerConnections();
|
|
209
215
|
await this.network.createSendTransport(this.media.mediasoupDevice);
|
|
210
216
|
await this.network.createRecvTransport(this.media.mediasoupDevice);
|
|
@@ -233,7 +233,7 @@ class PeerTrack {
|
|
|
233
233
|
|
|
234
234
|
try {
|
|
235
235
|
if (this.consumer.isAudio) {
|
|
236
|
-
this.#logger.warn('
|
|
236
|
+
this.#logger.warn('Only video consumers support layers', { case: 'requestVideoPreferredLayers' });
|
|
237
237
|
return;
|
|
238
238
|
}
|
|
239
239
|
|
|
@@ -242,7 +242,11 @@ class PeerTrack {
|
|
|
242
242
|
}
|
|
243
243
|
|
|
244
244
|
if (spatialLayer > this.consumer.spatialLayers) {
|
|
245
|
-
this.#logger.warn('
|
|
245
|
+
this.#logger.warn('Invalid spatial layer', {
|
|
246
|
+
spatialLayer,
|
|
247
|
+
consumerSpatialLayers: this.consumer.spatialLayers,
|
|
248
|
+
case: 'requestVideoPreferredLayers',
|
|
249
|
+
});
|
|
246
250
|
return;
|
|
247
251
|
}
|
|
248
252
|
|
|
@@ -264,9 +268,16 @@ class PeerTrack {
|
|
|
264
268
|
temporalLayer,
|
|
265
269
|
});
|
|
266
270
|
} catch (error) {
|
|
267
|
-
this.#logger.error('
|
|
268
|
-
|
|
271
|
+
this.#logger.error('Failed to request preferred layers', {
|
|
272
|
+
case: 'requestVideoPreferredLayers',
|
|
273
|
+
track: {
|
|
274
|
+
id: this.mediaStreamTrack.id,
|
|
275
|
+
kind: this.mediaStreamTrack.kind,
|
|
276
|
+
label: this.mediaStreamTrack.label,
|
|
277
|
+
},
|
|
269
278
|
consumerId: this.consumer.id,
|
|
279
|
+
spatialLayers: this.consumer.spatialLayers,
|
|
280
|
+
temporalLayers: this.consumer.temporalLayers,
|
|
270
281
|
error,
|
|
271
282
|
});
|
|
272
283
|
throw new Error('Error request preferred layers');
|
|
@@ -301,7 +312,7 @@ class PeerTrack {
|
|
|
301
312
|
}
|
|
302
313
|
|
|
303
314
|
if (this.consumer.isAudio) {
|
|
304
|
-
this.#logger.warn('
|
|
315
|
+
this.#logger.warn('Only video consumers support layers', { case: 'getVideoAvailableLayers' });
|
|
305
316
|
return undefined;
|
|
306
317
|
}
|
|
307
318
|
|
|
@@ -353,12 +364,11 @@ class PeerTrack {
|
|
|
353
364
|
|| spatialLayer < this.consumer.currentMaxSpatialLayer;
|
|
354
365
|
|
|
355
366
|
if (cantRequest) {
|
|
356
|
-
this.#logger.warn('
|
|
357
|
-
|
|
367
|
+
this.#logger.warn('Can`t request this spatial layer', {
|
|
368
|
+
case: 'requestMaxSpatialLayer',
|
|
358
369
|
consumerId,
|
|
359
370
|
spatialLayer,
|
|
360
371
|
});
|
|
361
|
-
|
|
362
372
|
return;
|
|
363
373
|
}
|
|
364
374
|
|
|
@@ -373,8 +383,8 @@ class PeerTrack {
|
|
|
373
383
|
spatialLayer,
|
|
374
384
|
});
|
|
375
385
|
} catch (error) {
|
|
376
|
-
this.#logger.warn('
|
|
377
|
-
|
|
386
|
+
this.#logger.warn('Failed to request max spatial layer', {
|
|
387
|
+
case: 'requestMaxSpatialLayer',
|
|
378
388
|
consumerId,
|
|
379
389
|
spatialLayer,
|
|
380
390
|
error,
|
package/src/helpers/media.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { types } from 'mediasoup-client';
|
|
1
|
+
import { Device, types } from 'mediasoup-client';
|
|
2
2
|
import Bowser from 'bowser';
|
|
3
|
+
import { RtpCodecCapability } from 'mediasoup-client/lib/RtpParameters';
|
|
3
4
|
|
|
4
5
|
// eslint-disable-next-line import/prefer-default-export
|
|
5
6
|
export const detectHandlerName = (userAgent?: string): types.BuiltinHandlerName | undefined => {
|
|
@@ -24,7 +25,7 @@ export const detectHandlerName = (userAgent?: string): types.BuiltinHandlerName
|
|
|
24
25
|
|
|
25
26
|
export const getNewAudioContext = (contextOptions?: AudioContextOptions): AudioContext | null => {
|
|
26
27
|
const Context = window.AudioContext // Default
|
|
27
|
-
|| (window as unknown as { webkitAudioContext
|
|
28
|
+
|| (window as unknown as { webkitAudioContext: any }).webkitAudioContext // Safari and old versions of Chrome
|
|
28
29
|
|| false;
|
|
29
30
|
|
|
30
31
|
if (Context) {
|
|
@@ -33,3 +34,16 @@ export const getNewAudioContext = (contextOptions?: AudioContextOptions): AudioC
|
|
|
33
34
|
|
|
34
35
|
return null;
|
|
35
36
|
};
|
|
37
|
+
|
|
38
|
+
export const getSupportedCodecsMimeTypes = (device: Device): string[] => device
|
|
39
|
+
.rtpCapabilities
|
|
40
|
+
.codecs
|
|
41
|
+
?.reduce((acc: string[], codec: RtpCodecCapability) => {
|
|
42
|
+
const preparedCodec = codec.mimeType?.toLowerCase();
|
|
43
|
+
|
|
44
|
+
if (!acc.includes(preparedCodec)) {
|
|
45
|
+
acc.push(preparedCodec);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return acc;
|
|
49
|
+
}, []) || [];
|
package/src/types/common.ts
CHANGED