@livedigital/client 2.25.0-webinar-highload-test.1 → 2.26.0-stop-streams.2
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/Peer.d.ts +2 -2
- package/dist/engine/index.d.ts +1 -0
- package/dist/engine/media/tracks/BaseTrack.d.ts +4 -1
- package/dist/engine/media/tracks/MediaStreamTrackManager.d.ts +14 -0
- package/dist/engine/media/tracks/PeerTrack.d.ts +2 -0
- package/dist/engine/media/tracks/VideoTrack.d.ts +2 -2
- package/dist/index.es.js +1 -1
- package/dist/index.js +2 -2
- package/dist/types/common.d.ts +12 -0
- package/package.json +1 -1
- package/src/engine/Peer.ts +10 -3
- package/src/engine/index.ts +26 -17
- package/src/engine/media/index.ts +16 -9
- package/src/engine/media/tracks/BaseTrack.ts +33 -7
- package/src/engine/media/tracks/MediaStreamTrackManager.ts +46 -0
- package/src/engine/media/tracks/PeerTrack.ts +14 -0
- package/src/engine/media/tracks/VideoTrack.ts +5 -2
- package/src/types/common.ts +15 -0
package/dist/types/common.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export declare type TrackProduceParams = {
|
|
|
20
20
|
codecOptions?: ProducerCodecOptions;
|
|
21
21
|
preferredCodec?: string;
|
|
22
22
|
transformParams?: TrackTransformParams;
|
|
23
|
+
keyFrameRequestDelay?: number;
|
|
23
24
|
};
|
|
24
25
|
export declare type TrackTransformParams = {
|
|
25
26
|
width?: number;
|
|
@@ -169,6 +170,10 @@ export declare type PayloadOfPublishedMedia = {
|
|
|
169
170
|
kind: MediaKind;
|
|
170
171
|
label: TrackLabel;
|
|
171
172
|
};
|
|
173
|
+
export declare type SubscribeOptions = {
|
|
174
|
+
producerId: string;
|
|
175
|
+
paused?: boolean;
|
|
176
|
+
};
|
|
172
177
|
export declare type PayloadOfUnpublishedMedia = PayloadOfPublishedMedia;
|
|
173
178
|
export declare type ChangePreferredLayersPayload = PreferredLayersParams & {
|
|
174
179
|
consumerId: string;
|
|
@@ -299,3 +304,10 @@ export declare type UpdatePeerAppDataPayload = {
|
|
|
299
304
|
peerId: string;
|
|
300
305
|
appData: Record<string, unknown>;
|
|
301
306
|
};
|
|
307
|
+
export declare type CreateTracksPayload = {
|
|
308
|
+
mediaStreamTracks: MediaStreamTrack[];
|
|
309
|
+
constraints: MediaStreamConstraints;
|
|
310
|
+
};
|
|
311
|
+
export declare type TrackPublishParams = {
|
|
312
|
+
keyFrameRequestDelay?: number;
|
|
313
|
+
};
|
package/package.json
CHANGED
package/src/engine/Peer.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
Role,
|
|
10
10
|
ProducerSetMaxSpatialLayer,
|
|
11
11
|
PeerInfo,
|
|
12
|
+
SubscribeOptions,
|
|
12
13
|
} from '../types/common';
|
|
13
14
|
import EnhancedEventEmitter from '../EnhancedEventEmitter';
|
|
14
15
|
import Engine from './index';
|
|
@@ -118,7 +119,7 @@ class Peer {
|
|
|
118
119
|
}));
|
|
119
120
|
}
|
|
120
121
|
|
|
121
|
-
public async subscribe(producerId:
|
|
122
|
+
public async subscribe({ producerId, paused = false }: SubscribeOptions): Promise<void> {
|
|
122
123
|
try {
|
|
123
124
|
const producer = this.producers.get(producerId);
|
|
124
125
|
if (!producer) {
|
|
@@ -132,7 +133,7 @@ class Peer {
|
|
|
132
133
|
return;
|
|
133
134
|
}
|
|
134
135
|
|
|
135
|
-
const { consumer } = await this.engine.network.createConsumer({
|
|
136
|
+
const { consumer, isProducerPaused } = await this.engine.network.createConsumer({
|
|
136
137
|
producerId: producer.id,
|
|
137
138
|
rtpCapabilities: this.engine.media.mediasoupDevice.rtpCapabilities,
|
|
138
139
|
producerPeerId: this.id,
|
|
@@ -147,9 +148,13 @@ class Peer {
|
|
|
147
148
|
engine: this.engine,
|
|
148
149
|
isPaused: true,
|
|
149
150
|
peerEventEmitter: this.observer,
|
|
151
|
+
isProducerPaused,
|
|
150
152
|
});
|
|
151
153
|
|
|
152
|
-
|
|
154
|
+
if (!paused) {
|
|
155
|
+
await track.resume();
|
|
156
|
+
}
|
|
157
|
+
|
|
153
158
|
this.tracks.set(track.label, track);
|
|
154
159
|
this.logger.debug(`Subscribed for ${producer.kind}`, { peer: this });
|
|
155
160
|
} catch (error) {
|
|
@@ -222,6 +227,7 @@ class Peer {
|
|
|
222
227
|
return;
|
|
223
228
|
}
|
|
224
229
|
|
|
230
|
+
track.setIsTrackProducerPaused(true);
|
|
225
231
|
await track.pause();
|
|
226
232
|
});
|
|
227
233
|
|
|
@@ -231,6 +237,7 @@ class Peer {
|
|
|
231
237
|
return;
|
|
232
238
|
}
|
|
233
239
|
|
|
240
|
+
track.setIsTrackProducerPaused(false);
|
|
234
241
|
await track.resume();
|
|
235
242
|
});
|
|
236
243
|
|
package/src/engine/index.ts
CHANGED
|
@@ -223,6 +223,12 @@ class Engine {
|
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
public removePeer(peerId: string): void {
|
|
226
|
+
const peer = this.peersRepository.get(peerId);
|
|
227
|
+
if (!peer) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
peer.tracks.forEach((track) => track.close());
|
|
226
232
|
this.peersRepository.delete(peerId);
|
|
227
233
|
}
|
|
228
234
|
|
|
@@ -451,20 +457,7 @@ class Engine {
|
|
|
451
457
|
|
|
452
458
|
private watchClientEvents(): void {
|
|
453
459
|
this.clientEventEmitter.on(INTERNAL_CLIENT_EVENTS.trackProduced, (track: Track) => {
|
|
454
|
-
|
|
455
|
-
if (!myPeer) {
|
|
456
|
-
return;
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
const peerTrack = new PeerTrack({
|
|
460
|
-
mediaStreamTrack: track.mediaStreamTrack,
|
|
461
|
-
label: track.getLabel(),
|
|
462
|
-
engine: this,
|
|
463
|
-
isPaused: track.isPaused,
|
|
464
|
-
peerEventEmitter: myPeer.observer,
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
myPeer.tracks.set(peerTrack.label, peerTrack);
|
|
460
|
+
this.createSelfPeerTrack(track);
|
|
468
461
|
});
|
|
469
462
|
|
|
470
463
|
this.clientEventEmitter.on(INTERNAL_CLIENT_EVENTS.trackUnproduced, (track: Track) => {
|
|
@@ -475,14 +468,30 @@ class Engine {
|
|
|
475
468
|
|
|
476
469
|
this.clientEventEmitter.on(INTERNAL_CLIENT_EVENTS.trackPaused, (track: Track) => {
|
|
477
470
|
const peerTrack = this.myPeer?.tracks.get(track.getLabel());
|
|
478
|
-
peerTrack?.
|
|
471
|
+
peerTrack?.close();
|
|
479
472
|
});
|
|
480
473
|
|
|
481
474
|
this.clientEventEmitter.on(INTERNAL_CLIENT_EVENTS.trackResumed, (track: Track) => {
|
|
482
|
-
|
|
483
|
-
peerTrack?.resume();
|
|
475
|
+
this.createSelfPeerTrack(track);
|
|
484
476
|
});
|
|
485
477
|
}
|
|
478
|
+
|
|
479
|
+
private createSelfPeerTrack(track: Track): void {
|
|
480
|
+
const myPeer = this.peersRepository.get(<string> this.mySocketId);
|
|
481
|
+
if (!myPeer) {
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
const peerTrack = new PeerTrack({
|
|
486
|
+
mediaStreamTrack: track.mediaStreamTrack,
|
|
487
|
+
label: track.getLabel(),
|
|
488
|
+
engine: this,
|
|
489
|
+
isPaused: track.isPaused,
|
|
490
|
+
peerEventEmitter: myPeer.observer,
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
myPeer.tracks.set(peerTrack.label, peerTrack);
|
|
494
|
+
}
|
|
486
495
|
}
|
|
487
496
|
|
|
488
497
|
export default Engine;
|
|
@@ -3,7 +3,11 @@ import { RtpCapabilities, RtpCodecCapability } from 'mediasoup-client/lib/RtpPar
|
|
|
3
3
|
import VideoTrack from './tracks/VideoTrack';
|
|
4
4
|
import AudioTrack from './tracks/AudioTrack';
|
|
5
5
|
import {
|
|
6
|
-
CreateScreenVideoTrackOptions,
|
|
6
|
+
CreateScreenVideoTrackOptions,
|
|
7
|
+
CreateTracksPayload,
|
|
8
|
+
CreateVideoTrackParams,
|
|
9
|
+
LogLevel,
|
|
10
|
+
Track,
|
|
7
11
|
} from '../../types/common';
|
|
8
12
|
import Logger from '../Logger';
|
|
9
13
|
import { VIDEO_CONSTRAINS } from '../../constants/videoConstrains';
|
|
@@ -11,6 +15,7 @@ import { SCREEN_SHARING_SIMULCAST_ENCODINGS, WEBCAM_SIMULCAST_ENCODINGS } from '
|
|
|
11
15
|
import { CreateMediaParams } from '../../types/engine';
|
|
12
16
|
import Engine from '../index';
|
|
13
17
|
import EnhancedEventEmitter from '../../EnhancedEventEmitter';
|
|
18
|
+
import MediaStreamTrackManager from './tracks/MediaStreamTrackManager';
|
|
14
19
|
|
|
15
20
|
class Media {
|
|
16
21
|
public isDeviceLoaded = false;
|
|
@@ -27,6 +32,8 @@ class Media {
|
|
|
27
32
|
|
|
28
33
|
readonly #clientEventEmitter: EnhancedEventEmitter;
|
|
29
34
|
|
|
35
|
+
readonly #mediaStreamTrackManager: MediaStreamTrackManager;
|
|
36
|
+
|
|
30
37
|
constructor(params: CreateMediaParams) {
|
|
31
38
|
this.#logLevel = params.logLevel;
|
|
32
39
|
this.#logger = new Logger({
|
|
@@ -35,6 +42,7 @@ class Media {
|
|
|
35
42
|
});
|
|
36
43
|
this.#engine = params.engine;
|
|
37
44
|
this.#clientEventEmitter = params.clientEventEmitter;
|
|
45
|
+
this.#mediaStreamTrackManager = new MediaStreamTrackManager(params.logLevel);
|
|
38
46
|
}
|
|
39
47
|
|
|
40
48
|
get mediasoupDevice(): Device {
|
|
@@ -62,20 +70,20 @@ class Media {
|
|
|
62
70
|
return codecs.find((c) => c.mimeType.toLowerCase() === `${track.kind}/${track.getPreferredCodec()}`);
|
|
63
71
|
}
|
|
64
72
|
|
|
65
|
-
private createTracks(
|
|
66
|
-
const mediaStreamTracks = stream.getTracks();
|
|
73
|
+
private createTracks({ constraints, mediaStreamTracks }: CreateTracksPayload): Track[] {
|
|
67
74
|
return mediaStreamTracks.map((mediaStreamTrack) => {
|
|
68
75
|
const params = {
|
|
69
76
|
mediaStreamTrack,
|
|
70
77
|
logLevel: this.#logLevel,
|
|
71
78
|
engine: this.#engine,
|
|
72
79
|
clientEventEmitter: this.#clientEventEmitter,
|
|
80
|
+
constraints,
|
|
81
|
+
mediaStreamTrackManager: this.#mediaStreamTrackManager,
|
|
73
82
|
};
|
|
74
83
|
|
|
75
84
|
const track = mediaStreamTrack.kind === 'audio' ? new AudioTrack(params) : new VideoTrack(params);
|
|
76
85
|
this.tracks.set(track.id, track);
|
|
77
86
|
this.#logger.debug('createTrack() track created', {
|
|
78
|
-
streamId: stream.id,
|
|
79
87
|
trackId: track.id,
|
|
80
88
|
kind: track.kind,
|
|
81
89
|
});
|
|
@@ -85,14 +93,13 @@ class Media {
|
|
|
85
93
|
}
|
|
86
94
|
|
|
87
95
|
async createUserMediaTracks(constraints: MediaStreamConstraints): Promise<Track[]> {
|
|
88
|
-
const
|
|
89
|
-
this
|
|
90
|
-
return this.createTracks(stream);
|
|
96
|
+
const mediaStreamTracks = await this.#mediaStreamTrackManager.createUserMediaTracks(constraints);
|
|
97
|
+
return this.createTracks({ constraints, mediaStreamTracks });
|
|
91
98
|
}
|
|
92
99
|
|
|
93
100
|
async createDisplayMediaTracks(constraints: MediaStreamConstraints): Promise<Track[]> {
|
|
94
|
-
const
|
|
95
|
-
return this.createTracks(
|
|
101
|
+
const mediaStreamTracks = await this.#mediaStreamTrackManager.createDisplayMediaTracks(constraints);
|
|
102
|
+
return this.createTracks({ constraints, mediaStreamTracks });
|
|
96
103
|
}
|
|
97
104
|
|
|
98
105
|
deleteTrack(track: Track) {
|
|
@@ -5,27 +5,31 @@ import {
|
|
|
5
5
|
EncoderConfig,
|
|
6
6
|
LogLevel,
|
|
7
7
|
SocketResponse,
|
|
8
|
-
TrackLabel,
|
|
8
|
+
TrackLabel,
|
|
9
|
+
TrackOutboundStats,
|
|
9
10
|
TrackProduceParams,
|
|
10
11
|
} from '../../../types/common';
|
|
11
12
|
import Logger from '../../Logger';
|
|
12
13
|
import Engine from '../../index';
|
|
13
14
|
import PeerConsumer from '../../PeerConsumer';
|
|
14
15
|
import { PRODUCER_CHECK_STATE_TIMEOUT } from '../../../constants/common';
|
|
15
|
-
import
|
|
16
|
-
import { MEDIASOUP_EVENTS, INTERNAL_CLIENT_EVENTS, CLIENT_EVENTS } from '../../../constants/events';
|
|
16
|
+
import { CLIENT_EVENTS, INTERNAL_CLIENT_EVENTS, MEDIASOUP_EVENTS } from '../../../constants/events';
|
|
17
17
|
import EnhancedEventEmitter from '../../../EnhancedEventEmitter';
|
|
18
18
|
import filterStatsCodecs from '../../../helpers/filterStatsCodecs';
|
|
19
|
+
import Timeout = NodeJS.Timeout;
|
|
20
|
+
import MediaStreamTrackManager from './MediaStreamTrackManager';
|
|
19
21
|
|
|
20
22
|
export type BaseTrackConstructorParams = {
|
|
21
23
|
mediaStreamTrack: MediaStreamTrack,
|
|
22
24
|
logLevel: LogLevel,
|
|
23
25
|
engine: Engine,
|
|
24
26
|
clientEventEmitter: EnhancedEventEmitter,
|
|
27
|
+
constraints: MediaStreamConstraints;
|
|
28
|
+
mediaStreamTrackManager: MediaStreamTrackManager;
|
|
25
29
|
};
|
|
26
30
|
|
|
27
31
|
class BaseTrack {
|
|
28
|
-
|
|
32
|
+
#mediaStreamTrack: MediaStreamTrack;
|
|
29
33
|
|
|
30
34
|
protected encoderConfig: EncoderConfig = {};
|
|
31
35
|
|
|
@@ -47,13 +51,19 @@ class BaseTrack {
|
|
|
47
51
|
|
|
48
52
|
#closed = false;
|
|
49
53
|
|
|
54
|
+
readonly #constraints: MediaStreamConstraints;
|
|
55
|
+
|
|
56
|
+
readonly #mediaStreamTrackManager: MediaStreamTrackManager;
|
|
57
|
+
|
|
50
58
|
constructor(params: BaseTrackConstructorParams) {
|
|
51
59
|
const {
|
|
52
|
-
mediaStreamTrack, logLevel, engine, clientEventEmitter,
|
|
60
|
+
mediaStreamTrack, logLevel, engine, clientEventEmitter, constraints, mediaStreamTrackManager,
|
|
53
61
|
} = params;
|
|
54
62
|
this.#mediaStreamTrack = mediaStreamTrack;
|
|
55
63
|
this.#engine = engine;
|
|
56
64
|
this.#clientEventEmitter = clientEventEmitter;
|
|
65
|
+
this.#constraints = constraints;
|
|
66
|
+
this.#mediaStreamTrackManager = mediaStreamTrackManager;
|
|
57
67
|
this.logger = new Logger({
|
|
58
68
|
namespace: 'Track',
|
|
59
69
|
logLevel,
|
|
@@ -212,6 +222,7 @@ class BaseTrack {
|
|
|
212
222
|
codecOptions,
|
|
213
223
|
trackTransformParams,
|
|
214
224
|
preferredCodec,
|
|
225
|
+
keyFrameRequestDelay,
|
|
215
226
|
},
|
|
216
227
|
} = this.producer;
|
|
217
228
|
|
|
@@ -222,6 +233,7 @@ class BaseTrack {
|
|
|
222
233
|
codecOptions,
|
|
223
234
|
transformParams: trackTransformParams,
|
|
224
235
|
preferredCodec,
|
|
236
|
+
keyFrameRequestDelay,
|
|
225
237
|
});
|
|
226
238
|
|
|
227
239
|
this.logger.debug('restartProducer()', { track: this });
|
|
@@ -257,6 +269,7 @@ class BaseTrack {
|
|
|
257
269
|
}
|
|
258
270
|
|
|
259
271
|
private async cancelProducerCheckState(): Promise<void> {
|
|
272
|
+
this.logger.debug('cancelProducerCheckState()', { track: this });
|
|
260
273
|
if (this.#checkStateTimeout) {
|
|
261
274
|
clearTimeout(this.#checkStateTimeout);
|
|
262
275
|
}
|
|
@@ -265,7 +278,11 @@ class BaseTrack {
|
|
|
265
278
|
}
|
|
266
279
|
|
|
267
280
|
async produce({
|
|
268
|
-
encodings,
|
|
281
|
+
encodings,
|
|
282
|
+
codecOptions,
|
|
283
|
+
preferredCodec,
|
|
284
|
+
transformParams,
|
|
285
|
+
keyFrameRequestDelay,
|
|
269
286
|
}: TrackProduceParams): Promise<void> {
|
|
270
287
|
if (!this.#engine.cahPublish) {
|
|
271
288
|
this.logger.error('produce()', { message: 'Not enough access to produce' });
|
|
@@ -285,6 +302,7 @@ class BaseTrack {
|
|
|
285
302
|
codecOptions,
|
|
286
303
|
preferredCodec,
|
|
287
304
|
codec,
|
|
305
|
+
keyFrameRequestDelay,
|
|
288
306
|
};
|
|
289
307
|
|
|
290
308
|
const producer = await this.#engine.network.sendTransport?.produce({
|
|
@@ -355,8 +373,10 @@ class BaseTrack {
|
|
|
355
373
|
}
|
|
356
374
|
|
|
357
375
|
try {
|
|
376
|
+
await this.cancelProducerCheckState();
|
|
358
377
|
await this.pauseRemoteProducer(this.producer.id);
|
|
359
378
|
this.producer.pause();
|
|
379
|
+
this.#mediaStreamTrack.stop();
|
|
360
380
|
this.clientEventEmitter.emit(INTERNAL_CLIENT_EVENTS.trackPaused, this);
|
|
361
381
|
this.logger.debug('pause()', { track: this });
|
|
362
382
|
} catch (error) {
|
|
@@ -372,10 +392,16 @@ class BaseTrack {
|
|
|
372
392
|
}
|
|
373
393
|
|
|
374
394
|
try {
|
|
395
|
+
const track = await this.#mediaStreamTrackManager.createMediaStreamTrack({
|
|
396
|
+
label: this.label,
|
|
397
|
+
constraints: this.#constraints,
|
|
398
|
+
});
|
|
399
|
+
this.#mediaStreamTrack = track;
|
|
400
|
+
await this.producer.replaceTrack({ track });
|
|
375
401
|
await this.resumeRemoteProducer(this.producer.id);
|
|
376
402
|
this.producer.resume();
|
|
377
403
|
this.clientEventEmitter.emit(INTERNAL_CLIENT_EVENTS.trackResumed, this);
|
|
378
|
-
this.logger.
|
|
404
|
+
this.logger.debug('resume()', { track: this });
|
|
379
405
|
} catch (error) {
|
|
380
406
|
this.logger.error('resume()', { error, track: this });
|
|
381
407
|
throw new Error('Can`t resume track');
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { LogLevel, TrackLabel } from '../../../types/common';
|
|
2
|
+
import Logger from '../../Logger';
|
|
3
|
+
|
|
4
|
+
export type GetMediaStreamTrackParams = {
|
|
5
|
+
label: TrackLabel;
|
|
6
|
+
constraints: MediaStreamConstraints;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
class MediaStreamTrackManager {
|
|
10
|
+
readonly #logger: Logger;
|
|
11
|
+
|
|
12
|
+
constructor(logLevel: LogLevel) {
|
|
13
|
+
this.#logger = new Logger({
|
|
14
|
+
namespace: 'MediaStreamTrackManager',
|
|
15
|
+
logLevel,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async createMediaStreamTrack({ label, constraints }: GetMediaStreamTrackParams): Promise<MediaStreamTrack> {
|
|
20
|
+
if (MediaStreamTrackManager.isDisplayMedia(label)) {
|
|
21
|
+
const [track] = await this.createDisplayMediaTracks(constraints);
|
|
22
|
+
return track;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const [track] = await this.createUserMediaTracks(constraints);
|
|
26
|
+
return track;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private static isDisplayMedia(label: TrackLabel): boolean {
|
|
30
|
+
return [TrackLabel.ScreenVideo, TrackLabel.ScreenAudio].includes(label);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async createUserMediaTracks(constraints: MediaStreamConstraints): Promise<MediaStreamTrack[]> {
|
|
34
|
+
const stream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
35
|
+
this.#logger.debug('createUserMediaTracks() stream created', { streamId: stream.id });
|
|
36
|
+
return stream.getTracks();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async createDisplayMediaTracks(constraints: MediaStreamConstraints): Promise<MediaStreamTrack[]> {
|
|
40
|
+
const stream = await navigator.mediaDevices.getDisplayMedia(constraints);
|
|
41
|
+
this.#logger.debug('getDisplayMediaTracks() stream created', { streamId: stream.id });
|
|
42
|
+
return stream.getTracks();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export default MediaStreamTrackManager;
|
|
@@ -20,6 +20,7 @@ interface PeerTrackConstructor {
|
|
|
20
20
|
consumer?: PeerConsumer,
|
|
21
21
|
engine: Engine,
|
|
22
22
|
isPaused: boolean,
|
|
23
|
+
isProducerPaused?: boolean,
|
|
23
24
|
peerEventEmitter: EnhancedEventEmitter,
|
|
24
25
|
}
|
|
25
26
|
|
|
@@ -44,6 +45,8 @@ class PeerTrack {
|
|
|
44
45
|
|
|
45
46
|
#closed = false;
|
|
46
47
|
|
|
48
|
+
#isTrackProducerPaused?: boolean;
|
|
49
|
+
|
|
47
50
|
constructor(payload: PeerTrackConstructor) {
|
|
48
51
|
this.#mediaStreamTrack = payload.mediaStreamTrack;
|
|
49
52
|
this.label = payload.label;
|
|
@@ -55,6 +58,7 @@ class PeerTrack {
|
|
|
55
58
|
});
|
|
56
59
|
this.#peerEventEmitter = payload.peerEventEmitter;
|
|
57
60
|
this.#paused = payload.isPaused;
|
|
61
|
+
this.#isTrackProducerPaused = payload.isProducerPaused;
|
|
58
62
|
this.#peerEventEmitter.safeEmit(PEER_EVENTS.trackStart, this);
|
|
59
63
|
}
|
|
60
64
|
|
|
@@ -131,11 +135,17 @@ class PeerTrack {
|
|
|
131
135
|
return;
|
|
132
136
|
}
|
|
133
137
|
|
|
138
|
+
if (this.#isTrackProducerPaused) {
|
|
139
|
+
this.#logger.debug('resume()', { message: 'Can not resume track, producer is paused', track: this, peer: this });
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
134
143
|
try {
|
|
135
144
|
await this.#engine.network.resumeRemoteConsumer(this.consumer.id);
|
|
136
145
|
this.consumer.resume();
|
|
137
146
|
this.#paused = false;
|
|
138
147
|
this.#peerEventEmitter.safeEmit(PEER_EVENTS.trackResumed, this);
|
|
148
|
+
this.checkConsumerState();
|
|
139
149
|
this.#logger.debug('resume()', { track: this, peer: this });
|
|
140
150
|
} catch (error) {
|
|
141
151
|
this.#logger.warn('resume()', { error });
|
|
@@ -427,6 +437,10 @@ class PeerTrack {
|
|
|
427
437
|
|
|
428
438
|
clearTimeout(this.#checkStateTimeout);
|
|
429
439
|
}
|
|
440
|
+
|
|
441
|
+
setIsTrackProducerPaused(value: boolean): void {
|
|
442
|
+
this.#isTrackProducerPaused = value;
|
|
443
|
+
}
|
|
430
444
|
}
|
|
431
445
|
|
|
432
446
|
export default PeerTrack;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { ProducerCodecOptions } from 'mediasoup-client/lib/Producer';
|
|
2
2
|
import { RtpEncodingParameters } from 'mediasoup-client/lib/RtpParameters';
|
|
3
3
|
import { WEBCAM_SIMULCAST_ENCODINGS } from '../../../constants/simulcastEncodings';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
TrackLabel, TrackPublishParams, VideoCodec, VideoEncoderConfig,
|
|
6
|
+
} from '../../../types/common';
|
|
5
7
|
import BaseTrack from './BaseTrack';
|
|
6
8
|
import TrackWithCodecOptions from './TrackWithCodecOptions';
|
|
7
9
|
import TrackWithEncodings from './TrackWithEncodings';
|
|
@@ -65,12 +67,13 @@ class VideoTrack extends BaseTrack implements TrackWithCodecOptions, TrackWithEn
|
|
|
65
67
|
return producer.maxSpatialLayer;
|
|
66
68
|
}
|
|
67
69
|
|
|
68
|
-
async publish(): Promise<void> {
|
|
70
|
+
async publish(params: TrackPublishParams = {}): Promise<void> {
|
|
69
71
|
await this.produce({
|
|
70
72
|
encodings: this.getEncodings(),
|
|
71
73
|
preferredCodec: this.getPreferredCodec(),
|
|
72
74
|
transformParams: this.transformParams,
|
|
73
75
|
codecOptions: this.getCodecOptions(),
|
|
76
|
+
keyFrameRequestDelay: params.keyFrameRequestDelay ?? 0,
|
|
74
77
|
});
|
|
75
78
|
|
|
76
79
|
this.clientEventEmitter.emit(INTERNAL_CLIENT_EVENTS.trackProduced, this);
|
package/src/types/common.ts
CHANGED
|
@@ -27,6 +27,7 @@ export type TrackProduceParams = {
|
|
|
27
27
|
codecOptions?: ProducerCodecOptions,
|
|
28
28
|
preferredCodec?: string,
|
|
29
29
|
transformParams?: TrackTransformParams,
|
|
30
|
+
keyFrameRequestDelay?: number,
|
|
30
31
|
};
|
|
31
32
|
|
|
32
33
|
export type TrackTransformParams = {
|
|
@@ -205,6 +206,11 @@ export type PayloadOfPublishedMedia = {
|
|
|
205
206
|
label: TrackLabel,
|
|
206
207
|
};
|
|
207
208
|
|
|
209
|
+
export type SubscribeOptions = {
|
|
210
|
+
producerId: string,
|
|
211
|
+
paused?: boolean,
|
|
212
|
+
};
|
|
213
|
+
|
|
208
214
|
export type PayloadOfUnpublishedMedia = PayloadOfPublishedMedia;
|
|
209
215
|
|
|
210
216
|
export type ChangePreferredLayersPayload = PreferredLayersParams & {
|
|
@@ -343,3 +349,12 @@ export type UpdatePeerAppDataPayload = {
|
|
|
343
349
|
peerId: string,
|
|
344
350
|
appData: Record<string, unknown>,
|
|
345
351
|
};
|
|
352
|
+
|
|
353
|
+
export type CreateTracksPayload = {
|
|
354
|
+
mediaStreamTracks: MediaStreamTrack[],
|
|
355
|
+
constraints: MediaStreamConstraints,
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
export type TrackPublishParams = {
|
|
359
|
+
keyFrameRequestDelay?: number;
|
|
360
|
+
};
|