@stream-io/video-client 1.33.0 → 1.33.1
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 +6 -0
- package/dist/index.browser.es.js +40 -20
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +40 -20
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +40 -20
- package/dist/index.es.js.map +1 -1
- package/dist/src/sorting/participants.d.ts +5 -2
- package/package.json +1 -1
- package/src/sorting/__tests__/sorting.test.ts +106 -0
- package/src/sorting/participants.ts +30 -14
- package/src/sorting/presets.ts +14 -2
|
@@ -47,9 +47,12 @@ export declare const pinned: Comparator<StreamVideoParticipant>;
|
|
|
47
47
|
* A comparator creator which will set up a comparator which prioritizes
|
|
48
48
|
* participants who are from a specific source (e.g., WebRTC, RTMP, WHIP...).
|
|
49
49
|
*
|
|
50
|
-
*
|
|
50
|
+
* The priority of a source is determined by the order of the sources passed in.
|
|
51
|
+
* e.g. [SRT, RTMP, WHIP] will prioritize SRT sources first, then RTMP, then WHIP.
|
|
52
|
+
*
|
|
53
|
+
* @param sources the sources to prioritize.
|
|
51
54
|
*/
|
|
52
|
-
export declare const withParticipantSource: (
|
|
55
|
+
export declare const withParticipantSource: (...sources: ParticipantSource[]) => Comparator<StreamVideoParticipant>;
|
|
53
56
|
/**
|
|
54
57
|
* A comparator creator which will set up a comparator which prioritizes
|
|
55
58
|
* participants who have a specific reaction.
|
package/package.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { ParticipantSource } from '../../gen/video/sfu/models/models';
|
|
2
3
|
import {
|
|
3
4
|
combineComparators,
|
|
4
5
|
Comparator,
|
|
@@ -8,6 +9,7 @@ import {
|
|
|
8
9
|
publishingAudio,
|
|
9
10
|
publishingVideo,
|
|
10
11
|
screenSharing,
|
|
12
|
+
withParticipantSource,
|
|
11
13
|
} from '../index';
|
|
12
14
|
import * as TestData from './participant-data';
|
|
13
15
|
|
|
@@ -43,4 +45,108 @@ describe('Sorting', () => {
|
|
|
43
45
|
const disableComparator = conditional<number>(() => false);
|
|
44
46
|
expect([...input].sort(disableComparator(byValue))).toEqual([2, 3, 1]);
|
|
45
47
|
});
|
|
48
|
+
|
|
49
|
+
it('withParticipantSource', () => {
|
|
50
|
+
expect(
|
|
51
|
+
withParticipantSource(ParticipantSource.SRT)(
|
|
52
|
+
// @ts-expect-error incomplete data
|
|
53
|
+
{ source: ParticipantSource.WEBRTC_UNSPECIFIED }, // -1
|
|
54
|
+
{ source: ParticipantSource.SRT }, // 0
|
|
55
|
+
),
|
|
56
|
+
).toEqual(1);
|
|
57
|
+
expect(
|
|
58
|
+
withParticipantSource(ParticipantSource.RTMP)(
|
|
59
|
+
// @ts-expect-error incomplete data
|
|
60
|
+
{ source: ParticipantSource.WEBRTC_UNSPECIFIED },
|
|
61
|
+
{ source: ParticipantSource.SIP },
|
|
62
|
+
),
|
|
63
|
+
).toEqual(0);
|
|
64
|
+
expect(
|
|
65
|
+
withParticipantSource(ParticipantSource.RTMP)(
|
|
66
|
+
// @ts-expect-error incomplete data
|
|
67
|
+
{ source: ParticipantSource.RTMP },
|
|
68
|
+
{ source: ParticipantSource.SIP },
|
|
69
|
+
),
|
|
70
|
+
).toEqual(-1);
|
|
71
|
+
expect(
|
|
72
|
+
withParticipantSource(ParticipantSource.RTMP)(
|
|
73
|
+
// @ts-expect-error incomplete data
|
|
74
|
+
{ source: ParticipantSource.SIP },
|
|
75
|
+
{ source: ParticipantSource.RTMP },
|
|
76
|
+
),
|
|
77
|
+
).toEqual(1);
|
|
78
|
+
expect(
|
|
79
|
+
withParticipantSource(ParticipantSource.RTMP)(
|
|
80
|
+
// @ts-expect-error incomplete data
|
|
81
|
+
{ source: ParticipantSource.WEBRTC_UNSPECIFIED },
|
|
82
|
+
{ source: ParticipantSource.RTMP },
|
|
83
|
+
),
|
|
84
|
+
).toEqual(1);
|
|
85
|
+
|
|
86
|
+
expect(
|
|
87
|
+
withParticipantSource(ParticipantSource.SRT, ParticipantSource.RTMP)(
|
|
88
|
+
// @ts-expect-error incomplete data
|
|
89
|
+
{ source: ParticipantSource.RTMP },
|
|
90
|
+
{ source: ParticipantSource.SRT },
|
|
91
|
+
),
|
|
92
|
+
).toEqual(1);
|
|
93
|
+
|
|
94
|
+
expect(
|
|
95
|
+
withParticipantSource(ParticipantSource.RTMP, ParticipantSource.SRT)(
|
|
96
|
+
// @ts-expect-error incomplete data
|
|
97
|
+
{ source: ParticipantSource.RTMP },
|
|
98
|
+
{ source: ParticipantSource.SRT },
|
|
99
|
+
),
|
|
100
|
+
).toEqual(-1);
|
|
101
|
+
expect(
|
|
102
|
+
withParticipantSource(ParticipantSource.RTMP, ParticipantSource.SRT)(
|
|
103
|
+
// @ts-expect-error incomplete data
|
|
104
|
+
{ source: ParticipantSource.WHIP },
|
|
105
|
+
{ source: ParticipantSource.SRT },
|
|
106
|
+
),
|
|
107
|
+
).toEqual(1);
|
|
108
|
+
|
|
109
|
+
expect(
|
|
110
|
+
withParticipantSource(
|
|
111
|
+
ParticipantSource.WHIP,
|
|
112
|
+
ParticipantSource.RTMP,
|
|
113
|
+
ParticipantSource.SRT,
|
|
114
|
+
)(
|
|
115
|
+
// @ts-expect-error incomplete data
|
|
116
|
+
{ source: ParticipantSource.WHIP },
|
|
117
|
+
{ source: ParticipantSource.SRT },
|
|
118
|
+
),
|
|
119
|
+
).toEqual(-1);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('withParticipantSources with multiple participants', () => {
|
|
123
|
+
const participants = [
|
|
124
|
+
{ source: ParticipantSource.WEBRTC_UNSPECIFIED },
|
|
125
|
+
{ source: ParticipantSource.SRT },
|
|
126
|
+
{ source: ParticipantSource.RTMP },
|
|
127
|
+
{ source: ParticipantSource.SIP },
|
|
128
|
+
{ source: ParticipantSource.RTSP },
|
|
129
|
+
{ source: ParticipantSource.WHIP },
|
|
130
|
+
];
|
|
131
|
+
|
|
132
|
+
const sorted = [...participants].sort(
|
|
133
|
+
withParticipantSource(
|
|
134
|
+
ParticipantSource.RTMP,
|
|
135
|
+
ParticipantSource.SRT,
|
|
136
|
+
ParticipantSource.WHIP,
|
|
137
|
+
ParticipantSource.RTSP,
|
|
138
|
+
ParticipantSource.SIP,
|
|
139
|
+
ParticipantSource.WEBRTC_UNSPECIFIED,
|
|
140
|
+
),
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
expect(sorted).toEqual([
|
|
144
|
+
{ source: ParticipantSource.RTMP },
|
|
145
|
+
{ source: ParticipantSource.SRT },
|
|
146
|
+
{ source: ParticipantSource.WHIP },
|
|
147
|
+
{ source: ParticipantSource.RTSP },
|
|
148
|
+
{ source: ParticipantSource.SIP },
|
|
149
|
+
{ source: ParticipantSource.WEBRTC_UNSPECIFIED },
|
|
150
|
+
]);
|
|
151
|
+
});
|
|
46
152
|
});
|
|
@@ -38,8 +38,10 @@ export const speaking: Comparator<StreamVideoParticipant> = (a, b) => {
|
|
|
38
38
|
* @param b the second participant.
|
|
39
39
|
*/
|
|
40
40
|
export const screenSharing: Comparator<StreamVideoParticipant> = (a, b) => {
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
const hasA = hasScreenShare(a);
|
|
42
|
+
const hasB = hasScreenShare(b);
|
|
43
|
+
if (hasA && !hasB) return -1;
|
|
44
|
+
if (!hasA && hasB) return 1;
|
|
43
45
|
return 0;
|
|
44
46
|
};
|
|
45
47
|
|
|
@@ -50,8 +52,10 @@ export const screenSharing: Comparator<StreamVideoParticipant> = (a, b) => {
|
|
|
50
52
|
* @param b the second participant.
|
|
51
53
|
*/
|
|
52
54
|
export const publishingVideo: Comparator<StreamVideoParticipant> = (a, b) => {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
const hasA = hasVideo(a);
|
|
56
|
+
const hasB = hasVideo(b);
|
|
57
|
+
if (hasA && !hasB) return -1;
|
|
58
|
+
if (!hasA && hasB) return 1;
|
|
55
59
|
return 0;
|
|
56
60
|
};
|
|
57
61
|
|
|
@@ -62,8 +66,10 @@ export const publishingVideo: Comparator<StreamVideoParticipant> = (a, b) => {
|
|
|
62
66
|
* @param b the second participant.
|
|
63
67
|
*/
|
|
64
68
|
export const publishingAudio: Comparator<StreamVideoParticipant> = (a, b) => {
|
|
65
|
-
|
|
66
|
-
|
|
69
|
+
const hasA = hasAudio(a);
|
|
70
|
+
const hasB = hasAudio(b);
|
|
71
|
+
if (hasA && !hasB) return -1;
|
|
72
|
+
if (!hasA && hasB) return 1;
|
|
67
73
|
return 0;
|
|
68
74
|
};
|
|
69
75
|
|
|
@@ -91,15 +97,23 @@ export const pinned: Comparator<StreamVideoParticipant> = (a, b) => {
|
|
|
91
97
|
* A comparator creator which will set up a comparator which prioritizes
|
|
92
98
|
* participants who are from a specific source (e.g., WebRTC, RTMP, WHIP...).
|
|
93
99
|
*
|
|
94
|
-
*
|
|
100
|
+
* The priority of a source is determined by the order of the sources passed in.
|
|
101
|
+
* e.g. [SRT, RTMP, WHIP] will prioritize SRT sources first, then RTMP, then WHIP.
|
|
102
|
+
*
|
|
103
|
+
* @param sources the sources to prioritize.
|
|
95
104
|
*/
|
|
96
|
-
export const withParticipantSource =
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
105
|
+
export const withParticipantSource = (
|
|
106
|
+
...sources: ParticipantSource[]
|
|
107
|
+
): Comparator<StreamVideoParticipant> => {
|
|
108
|
+
const priority = (i: number) => (i === -1 ? Number.MAX_SAFE_INTEGER : i);
|
|
109
|
+
return (a, b) => {
|
|
110
|
+
const priorityA = priority(sources.indexOf(a.source));
|
|
111
|
+
const priorityB = priority(sources.indexOf(b.source));
|
|
112
|
+
if (priorityA < priorityB) return -1;
|
|
113
|
+
if (priorityA > priorityB) return 1;
|
|
101
114
|
return 0;
|
|
102
115
|
};
|
|
116
|
+
};
|
|
103
117
|
|
|
104
118
|
/**
|
|
105
119
|
* A comparator creator which will set up a comparator which prioritizes
|
|
@@ -126,8 +140,10 @@ export const reactionType = (
|
|
|
126
140
|
export const role =
|
|
127
141
|
(...roles: string[]): Comparator<StreamVideoParticipant> =>
|
|
128
142
|
(a, b) => {
|
|
129
|
-
|
|
130
|
-
|
|
143
|
+
const hasA = hasAnyRole(a, roles);
|
|
144
|
+
const hasB = hasAnyRole(b, roles);
|
|
145
|
+
if (hasA && !hasB) return -1;
|
|
146
|
+
if (!hasA && hasB) return 1;
|
|
131
147
|
return 0;
|
|
132
148
|
};
|
|
133
149
|
|
package/src/sorting/presets.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ParticipantSource } from '../gen/video/sfu/models/models';
|
|
2
1
|
import { StreamVideoParticipant, VisibilityState } from '../types';
|
|
3
2
|
import { combineComparators, conditional } from './comparator';
|
|
3
|
+
import { ParticipantSource } from '../gen/video/sfu/models/models';
|
|
4
4
|
import {
|
|
5
5
|
dominantSpeaker,
|
|
6
6
|
pinned,
|
|
@@ -35,6 +35,16 @@ const ifInvisibleOrUnknownBy = conditional(
|
|
|
35
35
|
b.viewportVisibilityState?.videoTrack === VisibilityState.UNKNOWN,
|
|
36
36
|
);
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
* A comparator that prioritizes participants with video ingress sources.
|
|
40
|
+
*/
|
|
41
|
+
const withVideoIngressSource = withParticipantSource(
|
|
42
|
+
ParticipantSource.RTMP,
|
|
43
|
+
ParticipantSource.SRT,
|
|
44
|
+
ParticipantSource.WHIP,
|
|
45
|
+
ParticipantSource.RTSP,
|
|
46
|
+
);
|
|
47
|
+
|
|
38
48
|
/**
|
|
39
49
|
* The default sorting preset.
|
|
40
50
|
*/
|
|
@@ -63,6 +73,7 @@ export const speakerLayoutSortPreset = combineComparators(
|
|
|
63
73
|
combineComparators(
|
|
64
74
|
speaking,
|
|
65
75
|
reactionType('raised-hand'),
|
|
76
|
+
withVideoIngressSource,
|
|
66
77
|
publishingVideo,
|
|
67
78
|
publishingAudio,
|
|
68
79
|
),
|
|
@@ -80,6 +91,7 @@ export const paginatedLayoutSortPreset = combineComparators(
|
|
|
80
91
|
dominantSpeaker,
|
|
81
92
|
speaking,
|
|
82
93
|
reactionType('raised-hand'),
|
|
94
|
+
withVideoIngressSource,
|
|
83
95
|
publishingVideo,
|
|
84
96
|
publishingAudio,
|
|
85
97
|
),
|
|
@@ -95,7 +107,7 @@ export const livestreamOrAudioRoomSortPreset = combineComparators(
|
|
|
95
107
|
dominantSpeaker,
|
|
96
108
|
speaking,
|
|
97
109
|
reactionType('raised-hand'),
|
|
98
|
-
|
|
110
|
+
withVideoIngressSource,
|
|
99
111
|
publishingVideo,
|
|
100
112
|
publishingAudio,
|
|
101
113
|
),
|