@stream-io/video-react-sdk 0.0.1-alpha.9 → 0.0.1-alpha.91

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 (249) hide show
  1. package/CHANGELOG.md +22 -150
  2. package/README.md +1 -1
  3. package/dist/css/styles.css +273 -407
  4. package/dist/css/styles.css.map +1 -1
  5. package/dist/src/components/Button/CompositeButton.js +2 -4
  6. package/dist/src/components/Button/CompositeButton.js.map +1 -1
  7. package/dist/src/components/CallControls/AcceptCallButton.d.ts +7 -0
  8. package/dist/src/components/CallControls/AcceptCallButton.js +27 -0
  9. package/dist/src/components/CallControls/AcceptCallButton.js.map +1 -0
  10. package/dist/src/components/CallControls/CallControls.d.ts +1 -3
  11. package/dist/src/components/CallControls/CallControls.js +2 -5
  12. package/dist/src/components/CallControls/CallControls.js.map +1 -1
  13. package/dist/src/components/CallControls/CallStatsButton.d.ts +1 -5
  14. package/dist/src/components/CallControls/CallStatsButton.js +2 -4
  15. package/dist/src/components/CallControls/CallStatsButton.js.map +1 -1
  16. package/dist/src/components/CallControls/CancelCallButton.d.ts +2 -3
  17. package/dist/src/components/CallControls/CancelCallButton.js +4 -2
  18. package/dist/src/components/CallControls/CancelCallButton.js.map +1 -1
  19. package/dist/src/components/CallControls/ReactionsButton.js +1 -2
  20. package/dist/src/components/CallControls/ReactionsButton.js.map +1 -1
  21. package/dist/src/components/CallControls/RecordCallButton.d.ts +1 -3
  22. package/dist/src/components/CallControls/RecordCallButton.js +10 -6
  23. package/dist/src/components/CallControls/RecordCallButton.js.map +1 -1
  24. package/dist/src/components/CallControls/ScreenShareButton.d.ts +1 -3
  25. package/dist/src/components/CallControls/ScreenShareButton.js +7 -7
  26. package/dist/src/components/CallControls/ScreenShareButton.js.map +1 -1
  27. package/dist/src/components/CallControls/ToggleAudioButton.d.ts +1 -1
  28. package/dist/src/components/CallControls/ToggleAudioButton.js +17 -10
  29. package/dist/src/components/CallControls/ToggleAudioButton.js.map +1 -1
  30. package/dist/src/components/CallControls/ToggleVideoButton.d.ts +10 -0
  31. package/dist/src/components/CallControls/{ToggleCameraButton.js → ToggleVideoButton.js} +17 -11
  32. package/dist/src/components/CallControls/ToggleVideoButton.js.map +1 -0
  33. package/dist/src/components/CallControls/index.d.ts +2 -2
  34. package/dist/src/components/CallControls/index.js +2 -2
  35. package/dist/src/components/CallControls/index.js.map +1 -1
  36. package/dist/src/components/CallParticipantsList/BlockedUserListing.js +1 -2
  37. package/dist/src/components/CallParticipantsList/BlockedUserListing.js.map +1 -1
  38. package/dist/src/components/CallParticipantsList/CallParticipantListingItem.d.ts +2 -1
  39. package/dist/src/components/CallParticipantsList/CallParticipantListingItem.js +13 -5
  40. package/dist/src/components/CallParticipantsList/CallParticipantListingItem.js.map +1 -1
  41. package/dist/src/components/CallParticipantsList/CallParticipantsList.js +1 -2
  42. package/dist/src/components/CallParticipantsList/CallParticipantsList.js.map +1 -1
  43. package/dist/src/components/CallStats/CallStats.d.ts +6 -0
  44. package/dist/src/components/{StreamCall → CallStats}/CallStats.js +3 -3
  45. package/dist/src/components/CallStats/CallStats.js.map +1 -0
  46. package/dist/src/components/CallStats/CallStatsLatencyChart.js.map +1 -0
  47. package/dist/src/components/CallStats/index.d.ts +2 -0
  48. package/dist/src/components/CallStats/index.js +3 -0
  49. package/dist/src/components/CallStats/index.js.map +1 -0
  50. package/dist/src/components/Debug/DebugStatsView.d.ts +1 -1
  51. package/dist/src/components/Debug/DebugStatsView.js +32 -7
  52. package/dist/src/components/Debug/DebugStatsView.js.map +1 -1
  53. package/dist/src/components/DeviceSettings/DeviceSelectorAudio.js +5 -3
  54. package/dist/src/components/DeviceSettings/DeviceSelectorAudio.js.map +1 -1
  55. package/dist/src/components/DeviceSettings/DeviceSelectorVideo.js +3 -2
  56. package/dist/src/components/DeviceSettings/DeviceSelectorVideo.js.map +1 -1
  57. package/dist/src/components/Notification/SpeakingWhileMutedNotification.js +4 -2
  58. package/dist/src/components/Notification/SpeakingWhileMutedNotification.js.map +1 -1
  59. package/dist/src/components/PendingCallPanel/PendingCallControls.d.ts +2 -0
  60. package/dist/src/components/PendingCallPanel/PendingCallControls.js +13 -0
  61. package/dist/src/components/PendingCallPanel/PendingCallControls.js.map +1 -0
  62. package/dist/src/components/PendingCallPanel/PendingCallPanel.d.ts +2 -0
  63. package/dist/src/components/PendingCallPanel/PendingCallPanel.js +34 -0
  64. package/dist/src/components/PendingCallPanel/PendingCallPanel.js.map +1 -0
  65. package/dist/src/components/PendingCallPanel/index.d.ts +2 -0
  66. package/dist/src/components/PendingCallPanel/index.js +3 -0
  67. package/dist/src/components/PendingCallPanel/index.js.map +1 -0
  68. package/dist/src/components/Permissions/PermissionRequests.js +2 -8
  69. package/dist/src/components/Permissions/PermissionRequests.js.map +1 -1
  70. package/dist/src/components/StreamCall/CallParticipantsScreenView.js +3 -3
  71. package/dist/src/components/StreamCall/CallParticipantsScreenView.js.map +1 -1
  72. package/dist/src/components/StreamCall/CallParticipantsView.js +2 -3
  73. package/dist/src/components/StreamCall/CallParticipantsView.js.map +1 -1
  74. package/dist/src/components/StreamTheme/StreamTheme.d.ts +5 -0
  75. package/dist/src/components/StreamTheme/StreamTheme.js +18 -0
  76. package/dist/src/components/StreamTheme/StreamTheme.js.map +1 -0
  77. package/dist/src/components/StreamTheme/index.d.ts +1 -0
  78. package/dist/src/components/StreamTheme/index.js +2 -0
  79. package/dist/src/components/StreamTheme/index.js.map +1 -0
  80. package/dist/src/components/Video/VideoPreview.js +10 -5
  81. package/dist/src/components/Video/VideoPreview.js.map +1 -1
  82. package/dist/src/components/Video/index.d.ts +1 -1
  83. package/dist/src/components/Video/index.js +1 -1
  84. package/dist/src/components/Video/index.js.map +1 -1
  85. package/dist/src/components/index.d.ts +2 -2
  86. package/dist/src/components/index.js +2 -2
  87. package/dist/src/components/index.js.map +1 -1
  88. package/dist/src/core/components/CallLayout/PaginatedGridLayout.d.ts +3 -7
  89. package/dist/src/core/components/CallLayout/PaginatedGridLayout.js +13 -14
  90. package/dist/src/core/components/CallLayout/PaginatedGridLayout.js.map +1 -1
  91. package/dist/src/core/components/CallLayout/SpeakerLayout.d.ts +6 -1
  92. package/dist/src/core/components/CallLayout/SpeakerLayout.js +13 -7
  93. package/dist/src/core/components/CallLayout/SpeakerLayout.js.map +1 -1
  94. package/dist/src/core/components/ParticipantView/DefaultParticipantViewUI.d.ts +18 -0
  95. package/dist/src/core/components/ParticipantView/DefaultParticipantViewUI.js +36 -0
  96. package/dist/src/core/components/ParticipantView/DefaultParticipantViewUI.js.map +1 -0
  97. package/dist/src/core/components/ParticipantView/ParticipantView.d.ts +79 -0
  98. package/dist/src/core/components/ParticipantView/ParticipantView.js +33 -0
  99. package/dist/src/core/components/ParticipantView/ParticipantView.js.map +1 -0
  100. package/dist/src/core/components/ParticipantView/index.d.ts +2 -0
  101. package/dist/src/core/components/ParticipantView/index.js +3 -0
  102. package/dist/src/core/components/ParticipantView/index.js.map +1 -0
  103. package/dist/src/core/components/StreamCall/StreamCall.d.ts +73 -0
  104. package/dist/src/core/components/StreamCall/StreamCall.js +60 -0
  105. package/dist/src/core/components/StreamCall/StreamCall.js.map +1 -0
  106. package/dist/src/core/components/StreamCall/index.d.ts +1 -0
  107. package/dist/src/core/components/StreamCall/index.js +2 -0
  108. package/dist/src/core/components/StreamCall/index.js.map +1 -0
  109. package/dist/src/core/components/Video/BaseVideo.d.ts +3 -3
  110. package/dist/src/core/components/Video/BaseVideo.js +6 -12
  111. package/dist/src/core/components/Video/BaseVideo.js.map +1 -1
  112. package/dist/src/core/components/Video/DefaultVideoPlaceholder.d.ts +6 -0
  113. package/dist/src/core/components/Video/DefaultVideoPlaceholder.js +9 -0
  114. package/dist/src/core/components/Video/DefaultVideoPlaceholder.js.map +1 -0
  115. package/dist/src/core/components/Video/Video.d.ts +11 -6
  116. package/dist/src/core/components/Video/Video.js +31 -28
  117. package/dist/src/core/components/Video/Video.js.map +1 -1
  118. package/dist/src/core/components/index.d.ts +3 -2
  119. package/dist/src/core/components/index.js +2 -1
  120. package/dist/src/core/components/index.js.map +1 -1
  121. package/dist/src/core/contexts/MediaDevicesContext.d.ts +117 -19
  122. package/dist/src/core/contexts/MediaDevicesContext.js +52 -90
  123. package/dist/src/core/contexts/MediaDevicesContext.js.map +1 -1
  124. package/dist/src/core/hooks/index.d.ts +2 -0
  125. package/dist/src/core/hooks/index.js +2 -0
  126. package/dist/src/core/hooks/index.js.map +1 -1
  127. package/dist/src/core/hooks/useAudioPublisher.js +9 -3
  128. package/dist/src/core/hooks/useAudioPublisher.js.map +1 -1
  129. package/dist/src/core/hooks/useDevices.d.ts +80 -0
  130. package/dist/src/core/hooks/useDevices.js +113 -0
  131. package/dist/src/core/hooks/useDevices.js.map +1 -0
  132. package/dist/src/core/hooks/useTrackElementVisibility.d.ts +6 -0
  133. package/dist/src/core/hooks/useTrackElementVisibility.js +27 -0
  134. package/dist/src/core/hooks/useTrackElementVisibility.js.map +1 -0
  135. package/dist/src/core/hooks/useVideoPublisher.js +35 -6
  136. package/dist/src/core/hooks/useVideoPublisher.js.map +1 -1
  137. package/dist/src/hooks/index.d.ts +0 -1
  138. package/dist/src/hooks/index.js +0 -1
  139. package/dist/src/hooks/index.js.map +1 -1
  140. package/dist/src/utilities/applyElementToRef.d.ts +2 -0
  141. package/dist/src/utilities/applyElementToRef.js +8 -0
  142. package/dist/src/utilities/applyElementToRef.js.map +1 -0
  143. package/dist/src/utilities/chunk.d.ts +1 -0
  144. package/dist/src/utilities/chunk.js +5 -0
  145. package/dist/src/utilities/chunk.js.map +1 -0
  146. package/dist/src/utilities/index.d.ts +3 -0
  147. package/dist/src/utilities/index.js +4 -0
  148. package/dist/src/utilities/index.js.map +1 -0
  149. package/dist/src/utilities/isComponentType.d.ts +2 -0
  150. package/dist/src/utilities/isComponentType.js +7 -0
  151. package/dist/src/utilities/isComponentType.js.map +1 -0
  152. package/package.json +12 -10
  153. package/src/components/Button/CompositeButton.tsx +4 -13
  154. package/src/components/CallControls/AcceptCallButton.tsx +36 -0
  155. package/src/components/CallControls/CallControls.tsx +13 -19
  156. package/src/components/CallControls/CallStatsButton.tsx +6 -14
  157. package/src/components/CallControls/CancelCallButton.tsx +12 -4
  158. package/src/components/CallControls/ReactionsButton.tsx +1 -2
  159. package/src/components/CallControls/RecordCallButton.tsx +12 -7
  160. package/src/components/CallControls/ScreenShareButton.tsx +7 -8
  161. package/src/components/CallControls/ToggleAudioButton.tsx +23 -12
  162. package/src/components/CallControls/{ToggleCameraButton.tsx → ToggleVideoButton.tsx} +20 -13
  163. package/src/components/CallControls/index.ts +2 -2
  164. package/src/components/CallParticipantsList/BlockedUserListing.tsx +1 -2
  165. package/src/components/CallParticipantsList/CallParticipantListingItem.tsx +27 -3
  166. package/src/components/CallParticipantsList/CallParticipantsList.tsx +1 -1
  167. package/src/components/{StreamCall → CallStats}/CallStats.tsx +3 -3
  168. package/src/components/CallStats/index.ts +2 -0
  169. package/src/components/Debug/DebugStatsView.tsx +60 -7
  170. package/src/components/DeviceSettings/DeviceSelectorAudio.tsx +9 -4
  171. package/src/components/DeviceSettings/DeviceSelectorVideo.tsx +3 -3
  172. package/src/components/Notification/SpeakingWhileMutedNotification.tsx +9 -8
  173. package/src/components/PendingCallPanel/PendingCallControls.tsx +27 -0
  174. package/src/components/PendingCallPanel/PendingCallPanel.tsx +71 -0
  175. package/src/components/PendingCallPanel/index.ts +2 -0
  176. package/src/components/Permissions/PermissionRequests.tsx +2 -8
  177. package/src/components/StreamCall/CallParticipantsScreenView.tsx +3 -4
  178. package/src/components/StreamCall/CallParticipantsView.tsx +3 -4
  179. package/src/components/StreamTheme/StreamTheme.tsx +19 -0
  180. package/src/components/StreamTheme/index.ts +1 -0
  181. package/src/components/Video/VideoPreview.tsx +16 -6
  182. package/src/components/Video/index.ts +1 -1
  183. package/src/components/index.ts +2 -2
  184. package/src/core/components/CallLayout/PaginatedGridLayout.tsx +32 -36
  185. package/src/core/components/CallLayout/SpeakerLayout.tsx +48 -25
  186. package/src/core/components/ParticipantView/DefaultParticipantViewUI.tsx +160 -0
  187. package/src/core/components/ParticipantView/ParticipantView.tsx +156 -0
  188. package/src/core/components/ParticipantView/index.ts +2 -0
  189. package/src/core/components/StreamCall/StreamCall.tsx +157 -0
  190. package/src/core/components/StreamCall/index.ts +1 -0
  191. package/src/core/components/Video/BaseVideo.tsx +9 -24
  192. package/src/core/components/Video/DefaultVideoPlaceholder.tsx +36 -0
  193. package/src/core/components/Video/Video.tsx +62 -48
  194. package/src/core/components/index.ts +3 -2
  195. package/src/core/contexts/MediaDevicesContext.tsx +179 -136
  196. package/src/core/hooks/index.ts +2 -0
  197. package/src/core/hooks/useAudioPublisher.ts +9 -3
  198. package/src/core/hooks/useDevices.ts +161 -0
  199. package/src/core/hooks/useTrackElementVisibility.ts +44 -0
  200. package/src/core/hooks/useVideoPublisher.ts +36 -4
  201. package/src/hooks/index.ts +0 -1
  202. package/src/utilities/applyElementToRef.ts +12 -0
  203. package/src/utilities/chunk.ts +8 -0
  204. package/src/utilities/index.ts +3 -0
  205. package/src/utilities/isComponentType.ts +9 -0
  206. package/dist/src/components/CallControls/ToggleCameraButton.d.ts +0 -10
  207. package/dist/src/components/CallControls/ToggleCameraButton.js.map +0 -1
  208. package/dist/src/components/CallControls/ToggleParticipantListButton.d.ts +0 -6
  209. package/dist/src/components/CallControls/ToggleParticipantListButton.js +0 -7
  210. package/dist/src/components/CallControls/ToggleParticipantListButton.js.map +0 -1
  211. package/dist/src/components/Moderation/Restricted.d.ts +0 -19
  212. package/dist/src/components/Moderation/Restricted.js +0 -13
  213. package/dist/src/components/Moderation/Restricted.js.map +0 -1
  214. package/dist/src/components/Moderation/index.d.ts +0 -1
  215. package/dist/src/components/Moderation/index.js +0 -2
  216. package/dist/src/components/Moderation/index.js.map +0 -1
  217. package/dist/src/components/StreamCall/CallStats.d.ts +0 -2
  218. package/dist/src/components/StreamCall/CallStats.js.map +0 -1
  219. package/dist/src/components/StreamCall/CallStatsLatencyChart.js.map +0 -1
  220. package/dist/src/components/StreamMeeting/StreamMeeting.d.ts +0 -34
  221. package/dist/src/components/StreamMeeting/StreamMeeting.js +0 -26
  222. package/dist/src/components/StreamMeeting/StreamMeeting.js.map +0 -1
  223. package/dist/src/components/StreamMeeting/index.d.ts +0 -1
  224. package/dist/src/components/StreamMeeting/index.js +0 -2
  225. package/dist/src/components/StreamMeeting/index.js.map +0 -1
  226. package/dist/src/core/components/ParticipantBox/ParticipantBox.d.ts +0 -48
  227. package/dist/src/core/components/ParticipantBox/ParticipantBox.js +0 -58
  228. package/dist/src/core/components/ParticipantBox/ParticipantBox.js.map +0 -1
  229. package/dist/src/core/components/ParticipantBox/index.d.ts +0 -1
  230. package/dist/src/core/components/ParticipantBox/index.js +0 -2
  231. package/dist/src/core/components/ParticipantBox/index.js.map +0 -1
  232. package/dist/src/core/components/Video/VideoPlaceholder.d.ts +0 -6
  233. package/dist/src/core/components/Video/VideoPlaceholder.js +0 -12
  234. package/dist/src/core/components/Video/VideoPlaceholder.js.map +0 -1
  235. package/dist/src/hooks/useRtcStats.d.ts +0 -11
  236. package/dist/src/hooks/useRtcStats.js +0 -39
  237. package/dist/src/hooks/useRtcStats.js.map +0 -1
  238. package/src/components/CallControls/ToggleParticipantListButton.tsx +0 -17
  239. package/src/components/Moderation/Restricted.tsx +0 -38
  240. package/src/components/Moderation/index.ts +0 -1
  241. package/src/components/StreamMeeting/StreamMeeting.tsx +0 -80
  242. package/src/components/StreamMeeting/index.ts +0 -1
  243. package/src/core/components/ParticipantBox/ParticipantBox.tsx +0 -248
  244. package/src/core/components/ParticipantBox/index.ts +0 -1
  245. package/src/core/components/Video/VideoPlaceholder.tsx +0 -40
  246. package/src/hooks/useRtcStats.ts +0 -36
  247. /package/dist/src/components/{StreamCall → CallStats}/CallStatsLatencyChart.d.ts +0 -0
  248. /package/dist/src/components/{StreamCall → CallStats}/CallStatsLatencyChart.js +0 -0
  249. /package/src/components/{StreamCall → CallStats}/CallStatsLatencyChart.tsx +0 -0
@@ -1,5 +1,6 @@
1
1
  import { useCallback, useEffect, useState } from 'react';
2
2
  import {
3
+ Restricted,
3
4
  useCall,
4
5
  useHasPermissions,
5
6
  useLocalParticipant,
@@ -7,17 +8,16 @@ import {
7
8
 
8
9
  import { OwnCapability, SfuModels } from '@stream-io/video-client';
9
10
  import { CompositeButton, IconButton } from '../Button/';
10
- import { useMediaDevices } from '../../core/contexts';
11
+ import { DEVICE_STATE, useMediaDevices } from '../../core';
11
12
  import { DeviceSelectorVideo } from '../DeviceSettings';
12
13
  import { PermissionNotification } from '../Notification';
13
- import { Restricted } from '../Moderation';
14
14
 
15
- export type ToggleCameraPreviewButtonProps = { caption?: string };
15
+ export type ToggleVideoPreviewButtonProps = { caption?: string };
16
16
 
17
- export const ToggleCameraPreviewButton = ({
17
+ export const ToggleVideoPreviewButton = ({
18
18
  caption = 'Video',
19
- }: ToggleCameraPreviewButtonProps) => {
20
- const { toggleVideoMuteState, initialVideoState } = useMediaDevices();
19
+ }: ToggleVideoPreviewButtonProps) => {
20
+ const { toggleInitialVideoMuteState, initialVideoState } = useMediaDevices();
21
21
 
22
22
  return (
23
23
  <CompositeButton
@@ -27,20 +27,21 @@ export const ToggleCameraPreviewButton = ({
27
27
  >
28
28
  <IconButton
29
29
  icon={initialVideoState.enabled ? 'camera' : 'camera-off'}
30
- onClick={toggleVideoMuteState}
30
+ onClick={toggleInitialVideoMuteState}
31
31
  />
32
32
  </CompositeButton>
33
33
  );
34
34
  };
35
35
 
36
- type ToggleCameraPublishingButtonProps = {
36
+ type ToggleVideoPublishingButtonProps = {
37
37
  caption?: string;
38
38
  };
39
39
 
40
- export const ToggleCameraPublishingButton = ({
40
+ export const ToggleVideoPublishingButton = ({
41
41
  caption = 'Video',
42
- }: ToggleCameraPublishingButtonProps) => {
43
- const { publishVideoStream, stopPublishingVideo } = useMediaDevices();
42
+ }: ToggleVideoPublishingButtonProps) => {
43
+ const { publishVideoStream, stopPublishingVideo, setInitialVideoState } =
44
+ useMediaDevices();
44
45
  const localParticipant = useLocalParticipant();
45
46
  const isVideoMute = !localParticipant?.publishedTracks.includes(
46
47
  SfuModels.TrackType.VIDEO,
@@ -71,8 +72,13 @@ export const ToggleCameraPublishingButton = ({
71
72
  });
72
73
  return;
73
74
  }
74
- if (isVideoMute && hasPermission) {
75
- await publishVideoStream();
75
+ if (isVideoMute) {
76
+ if (hasPermission) {
77
+ setInitialVideoState(DEVICE_STATE.playing);
78
+ await publishVideoStream();
79
+ } else {
80
+ console.log('Cannot publish video. Insufficient permissions.');
81
+ }
76
82
  } else {
77
83
  stopPublishingVideo();
78
84
  }
@@ -81,6 +87,7 @@ export const ToggleCameraPublishingButton = ({
81
87
  hasPermission,
82
88
  isVideoMute,
83
89
  publishVideoStream,
90
+ setInitialVideoState,
84
91
  stopPublishingVideo,
85
92
  ]);
86
93
 
@@ -1,3 +1,4 @@
1
+ export * from './AcceptCallButton';
1
2
  export * from './CallControls';
2
3
  export * from './CallStatsButton';
3
4
  export * from './CancelCallButton';
@@ -5,6 +6,5 @@ export * from './ReactionsButton';
5
6
  export * from './RecordCallButton';
6
7
  export * from './ScreenShareButton';
7
8
  export * from './ToggleAudioButton';
8
- export * from './ToggleCameraButton';
9
9
  export * from './ToggleAudioOutputButton';
10
- export * from './ToggleParticipantListButton';
10
+ export * from './ToggleVideoButton';
@@ -1,7 +1,6 @@
1
- import { useCall } from '@stream-io/video-react-bindings';
1
+ import { Restricted, useCall } from '@stream-io/video-react-bindings';
2
2
  import { OwnCapability } from '@stream-io/video-client';
3
3
 
4
- import { Restricted } from '../Moderation';
5
4
  import { TextButton } from '../Button';
6
5
 
7
6
  export const BlockedUserListing = ({ data }: { data: string[] }) => {
@@ -1,6 +1,10 @@
1
1
  import clsx from 'clsx';
2
- import { ComponentProps, ComponentType, forwardRef } from 'react';
3
- import { useCall, useConnectedUser } from '@stream-io/video-react-bindings';
2
+ import { ComponentProps, ComponentType, forwardRef, useState } from 'react';
3
+ import {
4
+ Restricted,
5
+ useCall,
6
+ useConnectedUser,
7
+ } from '@stream-io/video-react-bindings';
4
8
  import {
5
9
  OwnCapability,
6
10
  SfuModels,
@@ -13,7 +17,6 @@ import {
13
17
  MenuToggle,
14
18
  ToggleMenuButtonProps,
15
19
  } from '../Menu';
16
- import { Restricted } from '../Moderation';
17
20
  import { WithTooltip } from '../Tooltip';
18
21
  import { Icon } from '../Icon';
19
22
 
@@ -116,9 +119,14 @@ const ToggleButton = forwardRef<HTMLButtonElement, ToggleMenuButtonProps>(
116
119
 
117
120
  export const ParticipantActionsContextMenu = ({
118
121
  participant,
122
+ participantViewElement,
119
123
  }: {
120
124
  participant: StreamVideoParticipant;
125
+ participantViewElement?: HTMLDivElement | null;
121
126
  }) => {
127
+ const [fullscreenModeOn, setFullscreenModeOn] = useState(
128
+ !!document.fullscreenElement,
129
+ );
122
130
  const activeCall = useCall();
123
131
 
124
132
  const blockUser = () => {
@@ -165,6 +173,19 @@ export const ParticipantActionsContextMenu = ({
165
173
  );
166
174
  };
167
175
 
176
+ const toggleFullscreenMode = () => {
177
+ if (!fullscreenModeOn)
178
+ return participantViewElement
179
+ ?.requestFullscreen()
180
+ .then(() => setFullscreenModeOn(true))
181
+ .catch(console.error);
182
+
183
+ document
184
+ .exitFullscreen()
185
+ .catch(console.error)
186
+ .finally(() => setFullscreenModeOn(false));
187
+ };
188
+
168
189
  return (
169
190
  <GenericMenu>
170
191
  <GenericMenuButtonItem onClick={toggleParticipantPinnedAt}>
@@ -211,6 +232,9 @@ export const ParticipantActionsContextMenu = ({
211
232
  Mute audio
212
233
  </GenericMenuButtonItem>
213
234
  </Restricted>
235
+ <GenericMenuButtonItem onClick={toggleFullscreenMode}>
236
+ {fullscreenModeOn ? 'Leave' : 'Enter'} fullscreen
237
+ </GenericMenuButtonItem>
214
238
  <Restricted requiredGrants={[OwnCapability.UPDATE_CALL_PERMISSIONS]}>
215
239
  <GenericMenuButtonItem
216
240
  onClick={grantPermission(OwnCapability.SEND_AUDIO)}
@@ -6,6 +6,7 @@ import {
6
6
  ComponentProps,
7
7
  } from 'react';
8
8
  import {
9
+ Restricted,
9
10
  useCall,
10
11
  useCallMetadata,
11
12
  useOwnCapabilities,
@@ -30,7 +31,6 @@ import { EmptyParticipantSearchList } from './EmptyParticipantSearchList';
30
31
  import { LoadingIndicator } from '../LoadingIndicator';
31
32
  import { SearchInput, SearchResults } from '../Search';
32
33
  import { useSearch, UseSearchParams } from '../Search/hooks';
33
- import { Restricted } from '../Moderation';
34
34
  import {
35
35
  GenericMenu,
36
36
  GenericMenuButtonItem,
@@ -3,7 +3,7 @@ import {
3
3
  AggregatedStatsReport,
4
4
  CallStatsReport,
5
5
  } from '@stream-io/video-client';
6
- import { useCurrentCallStatsReport } from '@stream-io/video-react-bindings';
6
+ import { useCallStatsReport } from '@stream-io/video-react-bindings';
7
7
  import { CallStatsLatencyChart } from './CallStatsLatencyChart';
8
8
 
9
9
  export const CallStats = () => {
@@ -17,7 +17,7 @@ export const CallStats = () => {
17
17
  const [publishBitrate, setPublishBitrate] = useState('-');
18
18
  const [subscribeBitrate, setSubscribeBitrate] = useState('-');
19
19
  const previousStats = useRef<CallStatsReport>();
20
- const callStatsReport = useCurrentCallStatsReport();
20
+ const callStatsReport = useCallStatsReport();
21
21
 
22
22
  useEffect(() => {
23
23
  if (!callStatsReport) return;
@@ -95,7 +95,7 @@ export const CallStats = () => {
95
95
  );
96
96
  };
97
97
 
98
- const StatCard = (props: { label: string; value: string }) => {
98
+ export const StatCard = (props: { label: string; value: string }) => {
99
99
  const { label, value } = props;
100
100
  return (
101
101
  <div className="str-video__call-stats__card">
@@ -0,0 +1,2 @@
1
+ export * from './CallStats';
2
+ export * from './CallStatsLatencyChart';
@@ -1,15 +1,26 @@
1
- import { useState } from 'react';
1
+ import { useEffect, useState } from 'react';
2
2
  import { Call } from '@stream-io/video-client';
3
- import { useRtcStats } from '../../hooks/useRtcStats';
4
3
  import { useFloatingUIPreset } from '../../hooks';
4
+ import { StatCard } from '../CallStats';
5
+ import { useCallStatsReport } from '@stream-io/video-react-bindings';
5
6
 
6
7
  export const DebugStatsView = (props: {
7
8
  call: Call;
8
- kind: 'subscriber' | 'publisher';
9
9
  mediaStream?: MediaStream;
10
+ sessionId: string;
10
11
  }) => {
11
- const { call, kind, mediaStream } = props;
12
- const stats = useRtcStats(call, kind, mediaStream);
12
+ const { call, mediaStream, sessionId } = props;
13
+ const callStatsReport = useCallStatsReport();
14
+
15
+ useEffect(() => {
16
+ call.startReportingStatsFor(sessionId);
17
+ return () => {
18
+ call.stopReportingStatsFor(sessionId);
19
+ };
20
+ }, [call, sessionId]);
21
+
22
+ const reportForTracks = callStatsReport?.participants[sessionId];
23
+ const trackStats = reportForTracks?.flatMap((report) => report.streams);
13
24
 
14
25
  const { refs, strategy, y, x } = useFloatingUIPreset({
15
26
  placement: 'top',
@@ -38,7 +49,7 @@ export const DebugStatsView = (props: {
38
49
  />
39
50
  {isPopperOpen && (
40
51
  <div
41
- className="str-video__debug__track-stats"
52
+ className="str-video__debug__track-stats str-video__call-stats"
42
53
  ref={refs.setFloating}
43
54
  style={{
44
55
  position: strategy,
@@ -47,9 +58,51 @@ export const DebugStatsView = (props: {
47
58
  overflowY: 'auto',
48
59
  }}
49
60
  >
50
- <pre>{JSON.stringify(stats, null, 2)}</pre>
61
+ <h3>Participant stats</h3>
62
+ <div className="str-video__call-stats__card-container">
63
+ {trackStats
64
+ ?.map((track) => {
65
+ if (track.kind === 'video') {
66
+ return (
67
+ <StatCard
68
+ key={`${track.rid}/${track.ssrc}/${track.codec}/${track.kind}`}
69
+ label={
70
+ `${track.kind}: ${track.codec} ` +
71
+ (track.rid ? ` (${track.rid})` : '')
72
+ }
73
+ value={`${track.frameWidth || 0}x${
74
+ track.frameHeight || 0
75
+ }@${track.framesPerSecond || 0}fps`}
76
+ />
77
+ );
78
+ } else if (track.kind === 'audio') {
79
+ return (
80
+ <StatCard
81
+ key={`${track.ssrc}/${track.codec}/${track.kind}`}
82
+ label={track.codec || 'N/A'}
83
+ value={`Jitter: ${track.jitter || 0}ms`}
84
+ />
85
+ );
86
+ }
87
+ return null;
88
+ })
89
+ .filter(Boolean)}
90
+ </div>
91
+ {reportForTracks?.map((report, index) => (
92
+ <pre key={index}>
93
+ {JSON.stringify(unwrapStats(report.rawStats), null, 2)}
94
+ </pre>
95
+ ))}
51
96
  </div>
52
97
  )}
53
98
  </>
54
99
  );
55
100
  };
101
+
102
+ const unwrapStats = (rawStats?: RTCStatsReport) => {
103
+ const decodedStats: Record<string, string> = {};
104
+ rawStats?.forEach((s) => {
105
+ decodedStats[s.id] = s;
106
+ });
107
+ return decodedStats;
108
+ };
@@ -1,5 +1,9 @@
1
1
  import { DeviceSelector } from './DeviceSelector';
2
- import { useMediaDevices } from '../../core/contexts';
2
+ import {
3
+ useMediaDevices,
4
+ useAudioInputDevices,
5
+ useAudioOutputDevices,
6
+ } from '../../core';
3
7
 
4
8
  export type DeviceSelectorAudioInputProps = {
5
9
  title?: string;
@@ -8,8 +12,8 @@ export type DeviceSelectorAudioInputProps = {
8
12
  export const DeviceSelectorAudioInput = ({
9
13
  title = 'Select a Mic',
10
14
  }: DeviceSelectorAudioInputProps) => {
11
- const { audioInputDevices, selectedAudioInputDeviceId, switchDevice } =
12
- useMediaDevices();
15
+ const { selectedAudioInputDeviceId, switchDevice } = useMediaDevices();
16
+ const audioInputDevices = useAudioInputDevices();
13
17
 
14
18
  return (
15
19
  <DeviceSelector
@@ -31,12 +35,13 @@ export const DeviceSelectorAudioOutput = ({
31
35
  title = 'Select speakers',
32
36
  }: DeviceSelectorAudioOutputProps) => {
33
37
  const {
34
- audioOutputDevices,
35
38
  isAudioOutputChangeSupported,
36
39
  selectedAudioOutputDeviceId,
37
40
  switchDevice,
38
41
  } = useMediaDevices();
39
42
 
43
+ const audioOutputDevices = useAudioOutputDevices();
44
+
40
45
  if (!isAudioOutputChangeSupported) return null;
41
46
 
42
47
  return (
@@ -1,13 +1,13 @@
1
1
  import { DeviceSelector } from './DeviceSelector';
2
- import { useMediaDevices } from '../../core/contexts';
2
+ import { useMediaDevices, useVideoDevices } from '../../core';
3
3
 
4
4
  export type DeviceSelectorVideoProps = {
5
5
  title?: string;
6
6
  };
7
7
 
8
8
  export const DeviceSelectorVideo = ({ title }: DeviceSelectorVideoProps) => {
9
- const { videoDevices, selectedVideoDeviceId, switchDevice } =
10
- useMediaDevices();
9
+ const { selectedVideoDeviceId, switchDevice } = useMediaDevices();
10
+ const videoDevices = useVideoDevices();
11
11
 
12
12
  return (
13
13
  <DeviceSelector
@@ -2,7 +2,7 @@ import { useEffect, useState } from 'react';
2
2
  import { createSoundDetector, SfuModels } from '@stream-io/video-client';
3
3
  import { useLocalParticipant } from '@stream-io/video-react-bindings';
4
4
 
5
- import { useMediaDevices } from '../../core/contexts';
5
+ import { useMediaDevices } from '../../core';
6
6
  import { Notification } from './Notification';
7
7
  import { ChildrenOnly } from '../../types';
8
8
 
@@ -18,13 +18,14 @@ export const SpeakingWhileMutedNotification = ({ children }: ChildrenOnly) => {
18
18
  useEffect(() => {
19
19
  // do nothing when not muted
20
20
  if (!isAudioMute) return;
21
- const disposeSoundDetector = getAudioStream(audioDeviceId).then(
22
- (audioStream) =>
23
- createSoundDetector(audioStream, (isSpeechDetected) => {
24
- setIsSpeakingWhileMuted((isNotified) =>
25
- isNotified ? isNotified : isSpeechDetected,
26
- );
27
- }),
21
+ const disposeSoundDetector = getAudioStream({
22
+ deviceId: audioDeviceId,
23
+ }).then((audioStream) =>
24
+ createSoundDetector(audioStream, (isSpeechDetected) => {
25
+ setIsSpeakingWhileMuted((isNotified) =>
26
+ isNotified ? isNotified : isSpeechDetected,
27
+ );
28
+ }),
28
29
  );
29
30
  disposeSoundDetector.catch((err) => {
30
31
  console.error('Error while creating sound detector', err);
@@ -0,0 +1,27 @@
1
+ import { CallingState } from '@stream-io/video-client';
2
+ import { AcceptCallButton, CancelCallButton } from '../CallControls';
3
+ import { useCall, useCallCallingState } from '@stream-io/video-react-bindings';
4
+
5
+ export const PendingCallControls = () => {
6
+ const call = useCall();
7
+ const callCallingState = useCallCallingState();
8
+
9
+ if (!call) return null;
10
+
11
+ const buttonsDisabled = callCallingState !== CallingState.RINGING;
12
+ return (
13
+ <div className="str-video__pending-call-controls">
14
+ {call.isCreatedByMe ? (
15
+ <CancelCallButton disabled={buttonsDisabled} />
16
+ ) : (
17
+ <>
18
+ <AcceptCallButton disabled={buttonsDisabled} />
19
+ <CancelCallButton
20
+ onClick={() => call.leave({ reject: true })}
21
+ disabled={buttonsDisabled}
22
+ />
23
+ </>
24
+ )}
25
+ </div>
26
+ );
27
+ };
@@ -0,0 +1,71 @@
1
+ import { CallingState } from '@stream-io/video-client';
2
+ import {
3
+ useCall,
4
+ useCallCallingState,
5
+ useCallMembers,
6
+ useCallMetadata,
7
+ useI18n,
8
+ } from '@stream-io/video-react-bindings';
9
+ import { Avatar } from '../Avatar';
10
+ import { PendingCallControls } from './PendingCallControls';
11
+
12
+ const CALLING_STATE_TO_LABEL: Record<CallingState, string> = {
13
+ [CallingState.JOINING]: 'Joining',
14
+ [CallingState.RINGING]: 'Ringing',
15
+ [CallingState.RECONNECTING]: 'Re-connecting',
16
+ [CallingState.RECONNECTING_FAILED]: 'Failed',
17
+ [CallingState.OFFLINE]: 'No internet connection',
18
+ [CallingState.IDLE]: '',
19
+ [CallingState.UNKNOWN]: '',
20
+ [CallingState.JOINED]: 'Joined',
21
+ [CallingState.LEFT]: 'Left call',
22
+ };
23
+
24
+ export const PendingCallPanel = () => {
25
+ const call = useCall();
26
+ const callingState = useCallCallingState();
27
+ const { t } = useI18n();
28
+ const metadata = useCallMetadata();
29
+ const members = useCallMembers();
30
+
31
+ if (!call) return null;
32
+
33
+ const caller = metadata?.created_by;
34
+ const membersToShow = call.isCreatedByMe
35
+ ? members
36
+ ?.slice(0, 3)
37
+ .map(({ user }) => user)
38
+ .filter((u) => !!u) || []
39
+ : caller
40
+ ? [caller]
41
+ : [];
42
+
43
+ const callingStateLabel = CALLING_STATE_TO_LABEL[callingState];
44
+
45
+ return (
46
+ <div className="str-video__call-panel str-video__call-panel--pending">
47
+ <div className="str-video__call-panel__members-list">
48
+ {membersToShow.map((user) => (
49
+ <div key={user.id} className="str-video__call-panel__member-box">
50
+ <Avatar name={user.name} imageSrc={user.image} />
51
+ {user.name && (
52
+ <div className="str-video__member_details">
53
+ <span className="str-video__member_name">{user.name}</span>
54
+ </div>
55
+ )}
56
+ </div>
57
+ ))}
58
+ </div>
59
+
60
+ {callingStateLabel && (
61
+ <div className="str-video__call-panel__calling-state-label">
62
+ {t(callingStateLabel)}
63
+ </div>
64
+ )}
65
+
66
+ {[CallingState.RINGING, CallingState.JOINING].includes(callingState) && (
67
+ <PendingCallControls />
68
+ )}
69
+ </div>
70
+ );
71
+ };
@@ -0,0 +1,2 @@
1
+ export * from './PendingCallControls';
2
+ export * from './PendingCallPanel';
@@ -53,15 +53,9 @@ export const PermissionRequests = () => {
53
53
  return async () => {
54
54
  const { user, permissions } = request;
55
55
  if (allow) {
56
- await call?.updateUserPermissions({
57
- user_id: user.id,
58
- grant_permissions: permissions,
59
- });
56
+ await call?.grantPermissions(user.id, permissions);
60
57
  } else {
61
- await call?.updateUserPermissions({
62
- user_id: user.id,
63
- revoke_permissions: permissions,
64
- });
58
+ await call?.revokePermissions(user.id, permissions);
65
59
  }
66
60
  setPermissionRequests((requests) =>
67
61
  requests.filter((r) => r !== request),
@@ -5,7 +5,7 @@ import {
5
5
  useLocalParticipant,
6
6
  useParticipants,
7
7
  } from '@stream-io/video-react-bindings';
8
- import { ParticipantBox } from '../../core/components/ParticipantBox/ParticipantBox';
8
+ import { ParticipantView, DefaultParticipantViewUI } from '../../core';
9
9
  import { Video } from '../Video';
10
10
 
11
11
  import { useVerticalScrollPosition } from './hooks';
@@ -60,7 +60,6 @@ export const CallParticipantsScreenView = (props: { call: Call }) => {
60
60
  <Video
61
61
  className="str-video__screen-share"
62
62
  participant={firstScreenSharingParticipant}
63
- call={call}
64
63
  kind="screen"
65
64
  autoPlay
66
65
  muted
@@ -104,11 +103,11 @@ export const CallParticipantsScreenView = (props: { call: Call }) => {
104
103
  >
105
104
  <div className="str-video__call-participants-screen-view__participants">
106
105
  {allParticipants.map((participant) => (
107
- <ParticipantBox
106
+ <ParticipantView
108
107
  key={participant.sessionId}
109
108
  participant={participant}
110
- call={call}
111
109
  sinkId={localParticipant?.audioOutputDeviceId}
110
+ ParticipantViewUI={DefaultParticipantViewUI}
112
111
  />
113
112
  ))}
114
113
  </div>
@@ -1,23 +1,22 @@
1
1
  import { Call } from '@stream-io/video-client';
2
- import { ParticipantBox } from '../../core/components/ParticipantBox/ParticipantBox';
2
+ import { DefaultParticipantViewUI, ParticipantView } from '../../core';
3
3
  import {
4
4
  useLocalParticipant,
5
5
  useParticipants,
6
6
  } from '@stream-io/video-react-bindings';
7
7
 
8
8
  export const CallParticipantsView = (props: { call: Call }) => {
9
- const { call } = props;
10
9
  const localParticipant = useLocalParticipant();
11
10
  const participants = useParticipants();
12
11
  const grid = `str-video__grid-${participants.length || 1}`;
13
12
  return (
14
13
  <div className={`str-video__call-participants-view ${grid}`}>
15
14
  {participants.map((participant) => (
16
- <ParticipantBox
15
+ <ParticipantView
17
16
  key={participant.sessionId}
18
17
  participant={participant}
19
- call={call}
20
18
  sinkId={localParticipant?.audioOutputDeviceId}
19
+ ParticipantViewUI={DefaultParticipantViewUI}
21
20
  />
22
21
  ))}
23
22
  </div>
@@ -0,0 +1,19 @@
1
+ import { ElementType, HTMLProps, PropsWithChildren } from 'react';
2
+ import clsx from 'clsx';
3
+
4
+ export type StreamThemeProps = HTMLProps<HTMLElement> & {
5
+ as?: ElementType;
6
+ };
7
+
8
+ export const StreamTheme = ({
9
+ as: Component = 'div',
10
+ className,
11
+ children,
12
+ ...props
13
+ }: PropsWithChildren<StreamThemeProps>) => {
14
+ return (
15
+ <Component {...props} className={clsx('str-video', className)}>
16
+ {children}
17
+ </Component>
18
+ );
19
+ };
@@ -0,0 +1 @@
1
+ export * from './StreamTheme';
@@ -7,8 +7,13 @@ import {
7
7
  } from 'react';
8
8
  import clsx from 'clsx';
9
9
  import { disposeOfMediaStream } from '@stream-io/video-client';
10
- import { BaseVideo } from '../../core/components/Video/BaseVideo';
11
- import { DEVICE_STATE, useMediaDevices } from '../../core/contexts';
10
+ import { BaseVideo } from '../../core/components/Video';
11
+ import {
12
+ DEVICE_STATE,
13
+ useMediaDevices,
14
+ useOnUnavailableVideoDevices,
15
+ useVideoDevices,
16
+ } from '../../core';
12
17
  import { LoadingIndicator } from '../LoadingIndicator';
13
18
 
14
19
  const DefaultDisabledVideoPreview = () => {
@@ -47,19 +52,24 @@ export const VideoPreview = ({
47
52
  VideoErrorPreview = DefaultVideoErrorPreview,
48
53
  }: VideoPreviewProps) => {
49
54
  const [stream, setStream] = useState<MediaStream>();
50
-
51
55
  const {
52
- videoDevices,
53
56
  selectedVideoDeviceId,
54
57
  getVideoStream,
55
58
  initialVideoState,
56
59
  setInitialVideoState,
57
60
  } = useMediaDevices();
61
+ // When there are 0 video devices (e.g. when laptop lid closed),
62
+ // we do not restart the video automatically when the device is again available,
63
+ // but rather leave turning the video on manually to the user.
64
+ useOnUnavailableVideoDevices(() =>
65
+ setInitialVideoState(DEVICE_STATE.stopped),
66
+ );
67
+ const videoDevices = useVideoDevices();
58
68
 
59
69
  useEffect(() => {
60
- if (!initialVideoState.enabled || videoDevices.length === 0) return;
70
+ if (!initialVideoState.enabled) return;
61
71
 
62
- getVideoStream(selectedVideoDeviceId)
72
+ getVideoStream({ deviceId: selectedVideoDeviceId })
63
73
  .then((s) => {
64
74
  setStream((previousStream) => {
65
75
  if (previousStream) {
@@ -1,4 +1,4 @@
1
1
  export * from '../../core/components/Video/Video';
2
2
  export * from '../../core/components/Video/BaseVideo';
3
- export * from '../../core/components/Video/VideoPlaceholder';
3
+ export * from '../../core/components/Video/DefaultVideoPlaceholder';
4
4
  export * from './VideoPreview';