@stream-io/video-client 1.16.4 → 1.16.5
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 +7 -0
- package/dist/index.browser.es.js +24 -8
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +24 -8
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +24 -8
- package/dist/index.es.js.map +1 -1
- package/dist/src/rtc/Publisher.d.ts +3 -0
- package/package.json +1 -1
- package/src/rtc/Publisher.ts +23 -6
- package/src/rtc/__tests__/Publisher.test.ts +19 -2
|
@@ -10,6 +10,7 @@ export type PublisherConstructorOpts = BasePeerConnectionOpts & {
|
|
|
10
10
|
*/
|
|
11
11
|
export declare class Publisher extends BasePeerConnection {
|
|
12
12
|
private readonly transceiverCache;
|
|
13
|
+
private readonly clonedTracks;
|
|
13
14
|
private publishOptions;
|
|
14
15
|
/**
|
|
15
16
|
* Constructs a new `Publisher` instance.
|
|
@@ -92,4 +93,6 @@ export declare class Publisher extends BasePeerConnection {
|
|
|
92
93
|
* Converts the given transceiver to a `TrackInfo` object.
|
|
93
94
|
*/
|
|
94
95
|
private toTrackInfo;
|
|
96
|
+
private cloneTrack;
|
|
97
|
+
private stopTrack;
|
|
95
98
|
}
|
package/package.json
CHANGED
package/src/rtc/Publisher.ts
CHANGED
|
@@ -31,6 +31,7 @@ export type PublisherConstructorOpts = BasePeerConnectionOpts & {
|
|
|
31
31
|
*/
|
|
32
32
|
export class Publisher extends BasePeerConnection {
|
|
33
33
|
private readonly transceiverCache = new TransceiverCache();
|
|
34
|
+
private readonly clonedTracks = new Set<MediaStreamTrack>();
|
|
34
35
|
private publishOptions: PublishOption[];
|
|
35
36
|
|
|
36
37
|
/**
|
|
@@ -79,6 +80,7 @@ export class Publisher extends BasePeerConnection {
|
|
|
79
80
|
dispose() {
|
|
80
81
|
super.dispose();
|
|
81
82
|
this.stopAllTracks();
|
|
83
|
+
this.clonedTracks.clear();
|
|
82
84
|
}
|
|
83
85
|
|
|
84
86
|
/**
|
|
@@ -100,7 +102,7 @@ export class Publisher extends BasePeerConnection {
|
|
|
100
102
|
|
|
101
103
|
// create a clone of the track as otherwise the same trackId will
|
|
102
104
|
// appear in the SDP in multiple transceivers
|
|
103
|
-
const trackToPublish =
|
|
105
|
+
const trackToPublish = this.cloneTrack(track);
|
|
104
106
|
|
|
105
107
|
const transceiver = this.transceiverCache.get(publishOption);
|
|
106
108
|
if (!transceiver) {
|
|
@@ -108,7 +110,7 @@ export class Publisher extends BasePeerConnection {
|
|
|
108
110
|
} else {
|
|
109
111
|
const previousTrack = transceiver.sender.track;
|
|
110
112
|
await transceiver.sender.replaceTrack(trackToPublish);
|
|
111
|
-
previousTrack
|
|
113
|
+
this.stopTrack(previousTrack);
|
|
112
114
|
}
|
|
113
115
|
}
|
|
114
116
|
};
|
|
@@ -153,7 +155,7 @@ export class Publisher extends BasePeerConnection {
|
|
|
153
155
|
|
|
154
156
|
// take the track from the existing transceiver for the same track type,
|
|
155
157
|
// clone it and publish it with the new publish options
|
|
156
|
-
const track = item.transceiver.sender.track
|
|
158
|
+
const track = this.cloneTrack(item.transceiver.sender.track!);
|
|
157
159
|
this.addTransceiver(track, publishOption);
|
|
158
160
|
}
|
|
159
161
|
|
|
@@ -167,7 +169,7 @@ export class Publisher extends BasePeerConnection {
|
|
|
167
169
|
);
|
|
168
170
|
if (hasPublishOption) continue;
|
|
169
171
|
// it is safe to stop the track here, it is a clone
|
|
170
|
-
transceiver.sender.track
|
|
172
|
+
this.stopTrack(transceiver.sender.track);
|
|
171
173
|
await transceiver.sender.replaceTrack(null);
|
|
172
174
|
}
|
|
173
175
|
};
|
|
@@ -209,7 +211,7 @@ export class Publisher extends BasePeerConnection {
|
|
|
209
211
|
for (const item of this.transceiverCache.items()) {
|
|
210
212
|
const { publishOption, transceiver } = item;
|
|
211
213
|
if (!trackTypes.includes(publishOption.trackType)) continue;
|
|
212
|
-
transceiver.sender.track
|
|
214
|
+
this.stopTrack(transceiver.sender.track);
|
|
213
215
|
}
|
|
214
216
|
};
|
|
215
217
|
|
|
@@ -218,7 +220,10 @@ export class Publisher extends BasePeerConnection {
|
|
|
218
220
|
*/
|
|
219
221
|
stopAllTracks = () => {
|
|
220
222
|
for (const { transceiver } of this.transceiverCache.items()) {
|
|
221
|
-
transceiver.sender.track
|
|
223
|
+
this.stopTrack(transceiver.sender.track);
|
|
224
|
+
}
|
|
225
|
+
for (const track of this.clonedTracks) {
|
|
226
|
+
this.stopTrack(track);
|
|
222
227
|
}
|
|
223
228
|
};
|
|
224
229
|
|
|
@@ -433,4 +438,16 @@ export class Publisher extends BasePeerConnection {
|
|
|
433
438
|
publishOptionId: publishOption.id,
|
|
434
439
|
};
|
|
435
440
|
};
|
|
441
|
+
|
|
442
|
+
private cloneTrack = (track: MediaStreamTrack): MediaStreamTrack => {
|
|
443
|
+
const clone = track.clone();
|
|
444
|
+
this.clonedTracks.add(clone);
|
|
445
|
+
return clone;
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
private stopTrack = (track: MediaStreamTrack | null | undefined) => {
|
|
449
|
+
if (!track) return;
|
|
450
|
+
track.stop();
|
|
451
|
+
this.clonedTracks.delete(track);
|
|
452
|
+
};
|
|
436
453
|
}
|
|
@@ -116,6 +116,7 @@ describe('Publisher', () => {
|
|
|
116
116
|
},
|
|
117
117
|
],
|
|
118
118
|
});
|
|
119
|
+
expect(publisher['clonedTracks'].size).toBe(1);
|
|
119
120
|
});
|
|
120
121
|
|
|
121
122
|
it('should update an existing transceiver for a new track', async () => {
|
|
@@ -597,10 +598,22 @@ describe('Publisher', () => {
|
|
|
597
598
|
);
|
|
598
599
|
vi.spyOn(inactiveTrack, 'readyState', 'get').mockReturnValue('ended');
|
|
599
600
|
|
|
601
|
+
const audioTransceiver = new RTCRtpTransceiver();
|
|
602
|
+
const audioTrack = new MediaStreamTrack();
|
|
603
|
+
vi.spyOn(audioTrack, 'kind', 'get').mockReturnValue('audio');
|
|
604
|
+
vi.spyOn(audioTrack, 'enabled', 'get').mockReturnValue(true);
|
|
605
|
+
vi.spyOn(audioTransceiver.sender, 'track', 'get').mockReturnValue(
|
|
606
|
+
audioTrack,
|
|
607
|
+
);
|
|
608
|
+
|
|
600
609
|
// @ts-expect-error incomplete data
|
|
601
610
|
cache.add({ trackType: TrackType.VIDEO, id: 1 }, transceiver);
|
|
602
611
|
// @ts-expect-error incomplete data
|
|
603
612
|
cache.add({ trackType: TrackType.VIDEO, id: 2 }, inactiveTransceiver);
|
|
613
|
+
// @ts-expect-error incomplete data
|
|
614
|
+
cache.add({ trackType: TrackType.AUDIO, id: 3 }, audioTransceiver);
|
|
615
|
+
|
|
616
|
+
publisher['clonedTracks'].add(track).add(inactiveTrack).add(audioTrack);
|
|
604
617
|
});
|
|
605
618
|
|
|
606
619
|
it('negotiate should set up the local and remote descriptions', async () => {
|
|
@@ -666,13 +679,13 @@ describe('Publisher', () => {
|
|
|
666
679
|
|
|
667
680
|
it('getPublishedTracks returns the published tracks', () => {
|
|
668
681
|
const tracks = publisher.getPublishedTracks();
|
|
669
|
-
expect(tracks).toHaveLength(
|
|
682
|
+
expect(tracks).toHaveLength(2);
|
|
670
683
|
expect(tracks[0].readyState).toBe('live');
|
|
671
684
|
});
|
|
672
685
|
|
|
673
686
|
it('getAnnouncedTracks should return all tracks', () => {
|
|
674
687
|
const trackInfos = publisher.getAnnouncedTracks('');
|
|
675
|
-
expect(trackInfos).toHaveLength(
|
|
688
|
+
expect(trackInfos).toHaveLength(3);
|
|
676
689
|
expect(trackInfos[0].muted).toBe(false);
|
|
677
690
|
expect(trackInfos[0].mid).toBe('0');
|
|
678
691
|
expect(trackInfos[1].muted).toBe(true);
|
|
@@ -701,15 +714,19 @@ describe('Publisher', () => {
|
|
|
701
714
|
it('stopTracks should stop tracks', () => {
|
|
702
715
|
const track = cache['cache'][0].transceiver.sender.track;
|
|
703
716
|
vi.spyOn(track, 'stop');
|
|
717
|
+
expect(publisher['clonedTracks'].size).toBe(3);
|
|
704
718
|
publisher.stopTracks(TrackType.VIDEO);
|
|
705
719
|
expect(track!.stop).toHaveBeenCalled();
|
|
720
|
+
expect(publisher['clonedTracks'].size).toBe(1);
|
|
706
721
|
});
|
|
707
722
|
|
|
708
723
|
it('stopAllTracks should stop all tracks', () => {
|
|
709
724
|
const track = cache['cache'][0].transceiver.sender.track;
|
|
710
725
|
vi.spyOn(track, 'stop');
|
|
726
|
+
expect(publisher['clonedTracks'].size).toBe(3);
|
|
711
727
|
publisher.stopAllTracks();
|
|
712
728
|
expect(track!.stop).toHaveBeenCalled();
|
|
729
|
+
expect(publisher['clonedTracks'].size).toBe(0);
|
|
713
730
|
});
|
|
714
731
|
});
|
|
715
732
|
});
|