@stream-io/video-react-sdk 1.14.2 → 1.14.4

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.
@@ -30,7 +30,7 @@ export type PipLayoutProps = {
30
30
  * @default true
31
31
  */
32
32
  mirrorLocalParticipantVideo?: boolean;
33
- } & Pick<ParticipantViewProps, 'ParticipantViewUI' | 'VideoPlaceholder' | 'PictureInPicturePlaceholder'>;
33
+ } & Pick<ParticipantViewProps, 'ParticipantViewUI' | 'VideoPlaceholder'>;
34
34
  export declare const PipLayout: {
35
35
  Pip: {
36
36
  (props: PipLayoutProps): import("react/jsx-runtime").JSX.Element | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stream-io/video-react-sdk",
3
- "version": "1.14.2",
3
+ "version": "1.14.4",
4
4
  "main": "./dist/index.cjs.js",
5
5
  "module": "./dist/index.es.js",
6
6
  "types": "./dist/index.d.ts",
@@ -30,9 +30,9 @@
30
30
  ],
31
31
  "dependencies": {
32
32
  "@floating-ui/react": "^0.27.6",
33
- "@stream-io/video-client": "1.19.2",
33
+ "@stream-io/video-client": "1.20.0",
34
34
  "@stream-io/video-filters-web": "0.1.7",
35
- "@stream-io/video-react-bindings": "1.5.14",
35
+ "@stream-io/video-react-bindings": "1.5.16",
36
36
  "chart.js": "^4.4.4",
37
37
  "clsx": "^2.0.0",
38
38
  "react-chartjs-2": "^5.3.0"
@@ -46,7 +46,7 @@
46
46
  "@rollup/plugin-replace": "^6.0.2",
47
47
  "@rollup/plugin-typescript": "^12.1.2",
48
48
  "@stream-io/audio-filters-web": "^0.2.3",
49
- "@stream-io/video-styling": "^1.1.3",
49
+ "@stream-io/video-styling": "^1.1.4",
50
50
  "@types/react": "^18.3.2",
51
51
  "@types/react-dom": "^18.3.0",
52
52
  "react": "^18.3.1",
@@ -1,4 +1,8 @@
1
- import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';
1
+ import {
2
+ useCall,
3
+ useCallStateHooks,
4
+ useI18n,
5
+ } from '@stream-io/video-react-bindings';
2
6
  import { useEffect, useState } from 'react';
3
7
 
4
8
  import { ParticipantsAudio } from '../Audio';
@@ -13,6 +17,8 @@ import {
13
17
  useFilteredParticipants,
14
18
  usePaginatedLayoutSortPreset,
15
19
  } from './hooks';
20
+ import { hasScreenShare } from '@stream-io/video-client';
21
+ import { Icon } from '../../../components';
16
22
 
17
23
  export type PipLayoutProps = {
18
24
  /**
@@ -46,19 +52,16 @@ export type PipLayoutProps = {
46
52
  * @default true
47
53
  */
48
54
  mirrorLocalParticipantVideo?: boolean;
49
- } & Pick<
50
- ParticipantViewProps,
51
- 'ParticipantViewUI' | 'VideoPlaceholder' | 'PictureInPicturePlaceholder'
52
- >;
55
+ } & Pick<ParticipantViewProps, 'ParticipantViewUI' | 'VideoPlaceholder'>;
53
56
 
54
57
  const Pip = (props: PipLayoutProps) => {
58
+ const { t } = useI18n();
55
59
  const {
56
60
  excludeLocalParticipant = false,
57
61
  filterParticipants,
58
62
  mirrorLocalParticipantVideo = true,
59
63
  VideoPlaceholder,
60
64
  ParticipantViewUI = DefaultParticipantViewUI,
61
- PictureInPicturePlaceholder,
62
65
  } = props;
63
66
  const [layoutWrapperElement, setLayoutWrapperElement] =
64
67
  useState<HTMLDivElement | null>(null);
@@ -68,6 +71,7 @@ const Pip = (props: PipLayoutProps) => {
68
71
  excludeLocalParticipant,
69
72
  filterParticipants,
70
73
  });
74
+ const screenSharingParticipant = participants.find((p) => hasScreenShare(p));
71
75
 
72
76
  usePaginatedLayoutSortPreset(call);
73
77
 
@@ -82,6 +86,24 @@ const Pip = (props: PipLayoutProps) => {
82
86
 
83
87
  return (
84
88
  <div className="str-video__pip-layout" ref={setLayoutWrapperElement}>
89
+ {screenSharingParticipant &&
90
+ (screenSharingParticipant.isLocalParticipant ? (
91
+ <div className="str-video__pip-screen-share-local">
92
+ <Icon icon="screen-share-off" />
93
+ <span className="str-video__pip-screen-share-local__title">
94
+ {t('You are presenting your screen')}
95
+ </span>
96
+ </div>
97
+ ) : (
98
+ <ParticipantView
99
+ participant={screenSharingParticipant}
100
+ trackType="screenShareTrack"
101
+ muteAudio
102
+ mirror={false}
103
+ VideoPlaceholder={VideoPlaceholder}
104
+ ParticipantViewUI={ParticipantViewUI}
105
+ />
106
+ ))}
85
107
  {participants.map((participant) => (
86
108
  <ParticipantView
87
109
  key={participant.sessionId}
@@ -89,7 +111,6 @@ const Pip = (props: PipLayoutProps) => {
89
111
  muteAudio
90
112
  mirror={mirror}
91
113
  VideoPlaceholder={VideoPlaceholder}
92
- PictureInPicturePlaceholder={PictureInPicturePlaceholder}
93
114
  ParticipantViewUI={ParticipantViewUI}
94
115
  />
95
116
  ))}
@@ -41,17 +41,36 @@ const defaultDevice = 'default';
41
41
  export const usePersistedDevicePreferences = (
42
42
  key: string = '@stream-io/device-preferences',
43
43
  ): void => {
44
- const { useCameraState, useMicrophoneState, useSpeakerState } =
45
- useCallStateHooks();
46
- usePersistedDevicePreference(key, 'camera', useCameraState());
47
- usePersistedDevicePreference(key, 'microphone', useMicrophoneState());
48
- usePersistedDevicePreference(key, 'speaker', useSpeakerState());
44
+ const {
45
+ useCallSettings,
46
+ useCameraState,
47
+ useMicrophoneState,
48
+ useSpeakerState,
49
+ } = useCallStateHooks();
50
+ const settings = useCallSettings();
51
+
52
+ usePersistedDevicePreference(
53
+ key,
54
+ 'camera',
55
+ useCameraState(),
56
+ settings ? !settings.video.camera_default_on : undefined,
57
+ );
58
+
59
+ usePersistedDevicePreference(
60
+ key,
61
+ 'microphone',
62
+ useMicrophoneState(),
63
+ settings ? !settings.audio.mic_default_on : undefined,
64
+ );
65
+
66
+ usePersistedDevicePreference(key, 'speaker', useSpeakerState(), false);
49
67
  };
50
68
 
51
69
  const usePersistedDevicePreference = <K extends DeviceKey>(
52
70
  key: string,
53
71
  deviceKey: K,
54
72
  state: DeviceState<K>,
73
+ defaultMuted?: boolean,
55
74
  ): void => {
56
75
  const { useCallCallingState } = useCallStateHooks();
57
76
  const callingState = useCallCallingState();
@@ -65,6 +84,7 @@ const usePersistedDevicePreference = <K extends DeviceKey>(
65
84
  if (
66
85
  callingState === CallingState.LEFT ||
67
86
  !state.devices?.length ||
87
+ typeof defaultMuted !== 'boolean' ||
68
88
  applyingState !== 'idle'
69
89
  ) {
70
90
  return;
@@ -75,8 +95,16 @@ const usePersistedDevicePreference = <K extends DeviceKey>(
75
95
 
76
96
  setApplyingState('applying');
77
97
 
78
- if (preference && !manager.state.selectedDevice) {
79
- applyLocalDevicePreference(manager, [preference].flat(), state.devices)
98
+ if (!manager.state.selectedDevice) {
99
+ const applyPromise = preference
100
+ ? applyLocalDevicePreference(
101
+ manager,
102
+ [preference].flat(),
103
+ state.devices,
104
+ )
105
+ : applyMutedState(manager, defaultMuted);
106
+
107
+ applyPromise
80
108
  .catch((err) => {
81
109
  console.warn(
82
110
  `Failed to apply ${deviceKey} device preferences`,
@@ -88,7 +116,15 @@ const usePersistedDevicePreference = <K extends DeviceKey>(
88
116
  setApplyingState('applied');
89
117
  }
90
118
  },
91
- [applyingState, callingState, deviceKey, key, manager, state.devices],
119
+ [
120
+ applyingState,
121
+ callingState,
122
+ defaultMuted,
123
+ deviceKey,
124
+ key,
125
+ manager,
126
+ state.devices,
127
+ ],
92
128
  );
93
129
 
94
130
  useEffect(
@@ -206,10 +242,14 @@ const applyLocalDevicePreference = async (
206
242
  }
207
243
 
208
244
  if (typeof muted === 'boolean') {
209
- await manager[muted ? 'disable' : 'enable']?.();
245
+ await applyMutedState(manager, muted);
210
246
  }
211
247
  };
212
248
 
249
+ const applyMutedState = async (manager: DeviceManagerLike, muted: boolean) => {
250
+ await manager[muted ? 'disable' : 'enable']?.();
251
+ };
252
+
213
253
  const getSelectedDevicePreference = (
214
254
  devices: MediaDeviceInfo[],
215
255
  selectedDevice: string | undefined,