@stream-io/video-client 1.14.0 → 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.
Files changed (92) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/index.browser.es.js +1532 -1784
  3. package/dist/index.browser.es.js.map +1 -1
  4. package/dist/index.cjs.js +1512 -1783
  5. package/dist/index.cjs.js.map +1 -1
  6. package/dist/index.es.js +1532 -1784
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/src/Call.d.ts +43 -28
  9. package/dist/src/StreamSfuClient.d.ts +4 -5
  10. package/dist/src/devices/CameraManager.d.ts +5 -8
  11. package/dist/src/devices/InputMediaDeviceManager.d.ts +5 -5
  12. package/dist/src/devices/MicrophoneManager.d.ts +7 -2
  13. package/dist/src/devices/ScreenShareManager.d.ts +1 -2
  14. package/dist/src/gen/video/sfu/event/events.d.ts +38 -19
  15. package/dist/src/gen/video/sfu/models/models.d.ts +76 -9
  16. package/dist/src/helpers/array.d.ts +7 -0
  17. package/dist/src/permissions/PermissionsContext.d.ts +6 -0
  18. package/dist/src/rtc/BasePeerConnection.d.ts +90 -0
  19. package/dist/src/rtc/Dispatcher.d.ts +0 -1
  20. package/dist/src/rtc/IceTrickleBuffer.d.ts +3 -2
  21. package/dist/src/rtc/Publisher.d.ts +32 -86
  22. package/dist/src/rtc/Subscriber.d.ts +4 -56
  23. package/dist/src/rtc/TransceiverCache.d.ts +55 -0
  24. package/dist/src/rtc/codecs.d.ts +1 -15
  25. package/dist/src/rtc/helpers/sdp.d.ts +8 -0
  26. package/dist/src/rtc/helpers/tracks.d.ts +1 -0
  27. package/dist/src/rtc/index.d.ts +3 -0
  28. package/dist/src/rtc/videoLayers.d.ts +11 -25
  29. package/dist/src/stats/{stateStoreStatsReporter.d.ts → CallStateStatsReporter.d.ts} +5 -1
  30. package/dist/src/stats/SfuStatsReporter.d.ts +4 -2
  31. package/dist/src/stats/index.d.ts +1 -1
  32. package/dist/src/stats/types.d.ts +8 -0
  33. package/dist/src/types.d.ts +12 -22
  34. package/package.json +1 -1
  35. package/src/Call.ts +254 -268
  36. package/src/StreamSfuClient.ts +9 -14
  37. package/src/StreamVideoClient.ts +1 -1
  38. package/src/__tests__/Call.publishing.test.ts +306 -0
  39. package/src/devices/CameraManager.ts +33 -16
  40. package/src/devices/InputMediaDeviceManager.ts +36 -27
  41. package/src/devices/MicrophoneManager.ts +29 -8
  42. package/src/devices/ScreenShareManager.ts +6 -8
  43. package/src/devices/__tests__/CameraManager.test.ts +111 -14
  44. package/src/devices/__tests__/InputMediaDeviceManager.test.ts +4 -4
  45. package/src/devices/__tests__/MicrophoneManager.test.ts +59 -21
  46. package/src/devices/__tests__/ScreenShareManager.test.ts +5 -5
  47. package/src/devices/__tests__/mocks.ts +1 -0
  48. package/src/events/__tests__/internal.test.ts +132 -0
  49. package/src/events/__tests__/mutes.test.ts +0 -3
  50. package/src/events/__tests__/speaker.test.ts +92 -0
  51. package/src/events/participant.ts +3 -4
  52. package/src/gen/video/sfu/event/events.ts +91 -30
  53. package/src/gen/video/sfu/models/models.ts +105 -13
  54. package/src/helpers/array.ts +14 -0
  55. package/src/permissions/PermissionsContext.ts +22 -0
  56. package/src/permissions/__tests__/PermissionsContext.test.ts +40 -0
  57. package/src/rpc/__tests__/createClient.test.ts +38 -0
  58. package/src/rpc/createClient.ts +11 -5
  59. package/src/rtc/BasePeerConnection.ts +240 -0
  60. package/src/rtc/Dispatcher.ts +0 -9
  61. package/src/rtc/IceTrickleBuffer.ts +24 -4
  62. package/src/rtc/Publisher.ts +210 -528
  63. package/src/rtc/Subscriber.ts +26 -200
  64. package/src/rtc/TransceiverCache.ts +120 -0
  65. package/src/rtc/__tests__/Publisher.test.ts +407 -210
  66. package/src/rtc/__tests__/Subscriber.test.ts +88 -36
  67. package/src/rtc/__tests__/mocks/webrtc.mocks.ts +22 -2
  68. package/src/rtc/__tests__/videoLayers.test.ts +161 -54
  69. package/src/rtc/codecs.ts +1 -131
  70. package/src/rtc/helpers/__tests__/rtcConfiguration.test.ts +34 -0
  71. package/src/rtc/helpers/__tests__/sdp.test.ts +59 -0
  72. package/src/rtc/helpers/sdp.ts +30 -0
  73. package/src/rtc/helpers/tracks.ts +3 -0
  74. package/src/rtc/index.ts +4 -0
  75. package/src/rtc/videoLayers.ts +68 -76
  76. package/src/stats/{stateStoreStatsReporter.ts → CallStateStatsReporter.ts} +58 -27
  77. package/src/stats/SfuStatsReporter.ts +31 -3
  78. package/src/stats/index.ts +1 -1
  79. package/src/stats/types.ts +12 -0
  80. package/src/types.ts +12 -22
  81. package/dist/src/helpers/sdp-munging.d.ts +0 -24
  82. package/dist/src/rtc/bitrateLookup.d.ts +0 -2
  83. package/dist/src/rtc/helpers/iceCandidate.d.ts +0 -2
  84. package/src/helpers/__tests__/hq-audio-sdp.ts +0 -332
  85. package/src/helpers/__tests__/sdp-munging.test.ts +0 -283
  86. package/src/helpers/sdp-munging.ts +0 -265
  87. package/src/rtc/__tests__/bitrateLookup.test.ts +0 -12
  88. package/src/rtc/__tests__/codecs.test.ts +0 -145
  89. package/src/rtc/bitrateLookup.ts +0 -61
  90. package/src/rtc/helpers/iceCandidate.ts +0 -16
  91. /package/dist/src/{compatibility.d.ts → helpers/compatibility.d.ts} +0 -0
  92. /package/src/{compatibility.ts → helpers/compatibility.ts} +0 -0
@@ -1,145 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
- import { getPreferredCodecs } from '../codecs';
3
- import './mocks/webrtc.mocks';
4
-
5
- describe('codecs', () => {
6
- it('should return preferred audio codec', () => {
7
- RTCRtpReceiver.getCapabilities = vi.fn().mockReturnValue(audioCodecs);
8
- const codecs = getPreferredCodecs('audio', 'red', undefined, 'receiver');
9
- expect(codecs).toBeDefined();
10
- expect(codecs?.map((c) => c.mimeType)).toEqual([
11
- 'audio/red',
12
- 'audio/opus',
13
- 'audio/G722',
14
- 'audio/PCMU',
15
- 'audio/PCMA',
16
- 'audio/CN',
17
- 'audio/telephone-event',
18
- ]);
19
- });
20
-
21
- it('should return preferred video codec', () => {
22
- RTCRtpReceiver.getCapabilities = vi.fn().mockReturnValue(videoCodecs);
23
- const codecs = getPreferredCodecs('video', 'vp8', undefined, 'receiver');
24
- expect(codecs).toBeDefined();
25
- // prettier-ignore
26
- expect(codecs?.map((c) => [c.mimeType, c.sdpFmtpLine])).toEqual([
27
- ['video/VP8', undefined],
28
- ['video/H264', 'level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640c1f'],
29
- ['video/rtx', undefined],
30
- ['video/H264', 'level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f'],
31
- ['video/H264', 'level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=640c1f'],
32
- ['video/H264', 'level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f'],
33
- ['video/VP9', 'profile-id=0'],
34
- ['video/VP9', 'profile-id=2'],
35
- ['video/red', undefined],
36
- ['video/ulpfec', undefined],
37
- ['video/flexfec-03', 'repair-window=10000000'],
38
- ]);
39
- });
40
-
41
- it('should pick the baseline H264 codec', () => {
42
- RTCRtpReceiver.getCapabilities = vi.fn().mockReturnValue(videoCodecs);
43
- const codecs = getPreferredCodecs('video', 'h264', undefined, 'receiver');
44
- expect(codecs).toBeDefined();
45
- // prettier-ignore
46
- expect(codecs?.map((c) => [c.mimeType, c.sdpFmtpLine])).toEqual([
47
- ['video/H264', 'level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f'],
48
- ['video/H264', 'level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f'],
49
- ['video/H264', 'level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640c1f'],
50
- ['video/H264', 'level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=640c1f'],
51
- ['video/rtx', undefined],
52
- ['video/VP8', undefined],
53
- ['video/VP9', 'profile-id=0'],
54
- ['video/VP9', 'profile-id=2'],
55
- ['video/red', undefined],
56
- ['video/ulpfec', undefined],
57
- ['video/flexfec-03', 'repair-window=10000000'],
58
- ]);
59
- });
60
-
61
- it('should pick the baseline H264 codec with optional packetization-mode', () => {
62
- RTCRtpReceiver.getCapabilities = vi
63
- .fn()
64
- .mockReturnValue(videoCodecsFirefox);
65
- const codecs = getPreferredCodecs('video', 'h264', undefined, 'receiver');
66
- expect(codecs).toBeDefined();
67
- // prettier-ignore
68
- expect(codecs?.map((c) => [c.mimeType, c.sdpFmtpLine])).toEqual([
69
- ['video/H264', 'profile-level-id=42e01f;level-asymmetry-allowed=1;packetization-mode=1'],
70
- ['video/H264', 'profile-level-id=42e01f;level-asymmetry-allowed=1'],
71
- ['video/VP8', 'max-fs=12288;max-fr=60'],
72
- ['video/rtx', undefined],
73
- ['video/VP9', 'max-fs=12288;max-fr=60'],
74
- ['video/ulpfec', undefined],
75
- ['video/red', undefined],
76
- ]);
77
- });
78
- });
79
-
80
- // prettier-ignore
81
- const videoCodecsFirefox: RTCRtpCapabilities = {
82
- codecs: [
83
- { mimeType: 'video/VP8', sdpFmtpLine: 'max-fs=12288;max-fr=60', clockRate: 90000 },
84
- { mimeType: 'video/rtx', clockRate: 90000 },
85
- { mimeType: 'video/VP9', sdpFmtpLine: 'max-fs=12288;max-fr=60', clockRate: 90000 },
86
- { mimeType: 'video/H264', sdpFmtpLine: 'profile-level-id=42e01f;level-asymmetry-allowed=1;packetization-mode=1', clockRate: 90000 },
87
- { mimeType: 'video/H264', sdpFmtpLine: 'profile-level-id=42e01f;level-asymmetry-allowed=1', clockRate: 90000 },
88
- { mimeType: 'video/ulpfec', clockRate: 90000 },
89
- { mimeType: 'video/red', clockRate: 90000 },
90
- ],
91
- headerExtensions: [
92
- { uri: 'urn:ietf:params:rtp-hdrext:sdes:mid' },
93
- { uri: 'http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time' },
94
- { uri: 'urn:ietf:params:rtp-hdrext:toffset' },
95
- { uri: 'http://www.webrtc.org/experiments/rtp-hdrext/playout-delay' },
96
- ],
97
- };
98
-
99
- // prettier-ignore
100
- const videoCodecs: RTCRtpCapabilities = {
101
- codecs: [
102
- { mimeType: 'video/H264', sdpFmtpLine: 'level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640c1f', clockRate: 90000 },
103
- { mimeType: 'video/rtx', clockRate: 90000 },
104
- { mimeType: 'video/H264', sdpFmtpLine: 'level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f', clockRate: 90000 },
105
- { mimeType: 'video/H264', sdpFmtpLine: 'level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=640c1f', clockRate: 90000 },
106
- { mimeType: 'video/H264', sdpFmtpLine: 'level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f', clockRate: 90000 },
107
- { mimeType: 'video/VP8', clockRate: 90000 },
108
- { mimeType: 'video/VP9', sdpFmtpLine: 'profile-id=0', clockRate: 90000 },
109
- { mimeType: 'video/VP9', sdpFmtpLine: 'profile-id=2', clockRate: 90000 },
110
- { mimeType: 'video/red', clockRate: 90000 },
111
- { mimeType: 'video/ulpfec', clockRate: 90000 },
112
- { mimeType: 'video/flexfec-03', sdpFmtpLine: 'repair-window=10000000', clockRate: 90000 },
113
- ],
114
- headerExtensions: [
115
- { uri: 'urn:ietf:params:rtp-hdrext:toffset' },
116
- { uri: 'http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time' },
117
- { uri: 'urn:3gpp:video-orientation' },
118
- { uri: 'http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01' },
119
- { uri: 'http://www.webrtc.org/experiments/rtp-hdrext/playout-delay' },
120
- { uri: 'http://www.webrtc.org/experiments/rtp-hdrext/video-content-type' },
121
- { uri: 'http://www.webrtc.org/experiments/rtp-hdrext/video-timing' },
122
- { uri: 'http://www.webrtc.org/experiments/rtp-hdrext/color-space' },
123
- { uri: 'urn:ietf:params:rtp-hdrext:sdes:mid' },
124
- { uri: 'urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id' },
125
- { uri: 'urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id' },
126
- ],
127
- };
128
-
129
- // prettier-ignore
130
- const audioCodecs: RTCRtpCapabilities = {
131
- codecs: [
132
- { mimeType: 'audio/opus', sdpFmtpLine: 'minptime=10;useinbandfec=1', clockRate: 48000 },
133
- { mimeType: 'audio/red', sdpFmtpLine: '=111/111', clockRate: 48000 },
134
- { mimeType: 'audio/G722', clockRate: 8000, channels: 1 },
135
- { mimeType: 'audio/PCMU', clockRate: 8000, channels: 1 },
136
- { mimeType: 'audio/PCMA', clockRate: 8000, channels: 1 },
137
- { mimeType: 'audio/CN', clockRate: 8000, channels: 1 },
138
- { mimeType: 'audio/telephone-event', clockRate: 8000, channels: 1 },
139
- ],
140
- headerExtensions: [
141
- { uri: 'urn:ietf:params:rtp-hdrext:ssrc-audio-level' },
142
- { uri: 'http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time' },
143
- { uri: 'urn:ietf:params:rtp-hdrext:sdes:mid' },
144
- ],
145
- };
@@ -1,61 +0,0 @@
1
- import { PreferredCodec } from '../types';
2
-
3
- const bitrateLookupTable: Record<
4
- PreferredCodec,
5
- Record<number | 'default', number | undefined> | undefined
6
- > = {
7
- h264: {
8
- 2160: 5_000_000,
9
- 1440: 3_000_000,
10
- 1080: 2_000_000,
11
- 720: 1_250_000,
12
- 540: 750_000,
13
- 360: 400_000,
14
- default: 1_250_000,
15
- },
16
- vp8: {
17
- 2160: 5_000_000,
18
- 1440: 2_750_000,
19
- 1080: 2_000_000,
20
- 720: 1_250_000,
21
- 540: 600_000,
22
- 360: 350_000,
23
- default: 1_250_000,
24
- },
25
- vp9: {
26
- 2160: 3_000_000,
27
- 1440: 2_000_000,
28
- 1080: 1_500_000,
29
- 720: 1_250_000,
30
- 540: 500_000,
31
- 360: 275_000,
32
- default: 1_250_000,
33
- },
34
- av1: {
35
- 2160: 2_000_000,
36
- 1440: 1_550_000,
37
- 1080: 1_000_000,
38
- 720: 600_000,
39
- 540: 350_000,
40
- 360: 200_000,
41
- default: 600_000,
42
- },
43
- };
44
-
45
- export const getOptimalBitrate = (
46
- codec: PreferredCodec,
47
- frameHeight: number,
48
- ): number => {
49
- const codecLookup = bitrateLookupTable[codec];
50
- if (!codecLookup) throw new Error(`Unknown codec: ${codec}`);
51
-
52
- let bitrate = codecLookup[frameHeight];
53
- if (!bitrate) {
54
- const keys = Object.keys(codecLookup).map(Number);
55
- const nearest = keys.reduce((a, b) =>
56
- Math.abs(b - frameHeight) < Math.abs(a - frameHeight) ? b : a,
57
- );
58
- bitrate = codecLookup[nearest];
59
- }
60
- return bitrate ?? codecLookup.default!;
61
- };
@@ -1,16 +0,0 @@
1
- import { ICETrickle } from '../../gen/video/sfu/models/models';
2
-
3
- export function getIceCandidate(
4
- candidate: RTCIceCandidate,
5
- ): ICETrickle['iceCandidate'] {
6
- if (!candidate.usernameFragment) {
7
- // react-native-webrtc doesn't include usernameFragment in the candidate
8
- const splittedCandidate = candidate.candidate.split(' ');
9
- const ufragIndex =
10
- splittedCandidate.findIndex((s: string) => s === 'ufrag') + 1;
11
- const usernameFragment = splittedCandidate[ufragIndex];
12
- return JSON.stringify({ ...candidate, usernameFragment });
13
- } else {
14
- return JSON.stringify(candidate.toJSON());
15
- }
16
- }