@stream-io/video-react-sdk 0.3.46 → 0.4.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.
- package/CHANGELOG.md +22 -0
- package/README.md +3 -2
- package/dist/index.cjs.js +328 -885
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.es.js +329 -870
- package/dist/index.es.js.map +1 -1
- package/dist/src/components/CallControls/ScreenShareButton.d.ts +1 -1
- package/dist/src/components/Notification/SpeakingWhileMutedNotification.d.ts +3 -0
- package/dist/src/components/{Video → VideoPreview}/VideoPreview.d.ts +1 -9
- package/dist/src/components/index.d.ts +1 -1
- package/dist/src/core/components/ParticipantView/ParticipantView.d.ts +3 -9
- package/dist/src/core/components/ParticipantView/ParticipantViewContext.d.ts +9 -0
- package/dist/src/core/components/ParticipantView/index.d.ts +1 -0
- package/dist/src/core/components/StreamCall/StreamCall.d.ts +2 -11
- package/dist/src/core/hooks/index.d.ts +0 -2
- package/dist/src/core/hooks/useDevices.d.ts +0 -99
- package/dist/src/core/index.d.ts +0 -1
- package/dist/src/hooks/index.d.ts +1 -3
- package/dist/src/hooks/usePersistedDevicePreferences.d.ts +13 -0
- package/dist/src/translations/index.d.ts +2 -0
- package/index.ts +2 -2
- package/package.json +3 -3
- package/src/components/CallControls/CallControls.tsx +6 -8
- package/src/components/CallControls/ScreenShareButton.tsx +17 -13
- package/src/components/CallControls/ToggleAudioButton.tsx +21 -24
- package/src/components/CallControls/ToggleAudioOutputButton.tsx +1 -1
- package/src/components/CallControls/ToggleVideoButton.tsx +21 -22
- package/src/components/CallParticipantsList/CallParticipantsList.tsx +1 -1
- package/src/components/DeviceSettings/DeviceSelectorAudio.tsx +20 -26
- package/src/components/DeviceSettings/DeviceSelectorVideo.tsx +9 -8
- package/src/components/Icon/Icon.tsx +1 -1
- package/src/components/Notification/SpeakingWhileMutedNotification.tsx +5 -49
- package/src/components/VideoPreview/VideoPreview.tsx +67 -0
- package/src/components/index.ts +1 -1
- package/src/core/components/CallLayout/PaginatedGridLayout.tsx +2 -5
- package/src/core/components/ParticipantView/DefaultParticipantViewUI.tsx +7 -6
- package/src/core/components/ParticipantView/ParticipantView.tsx +2 -19
- package/src/core/components/ParticipantView/ParticipantViewContext.tsx +17 -0
- package/src/core/components/ParticipantView/index.ts +1 -0
- package/src/core/components/StreamCall/StreamCall.tsx +2 -28
- package/src/core/hooks/index.ts +0 -2
- package/src/core/hooks/useDevices.ts +0 -195
- package/src/core/index.ts +0 -1
- package/src/hooks/index.ts +1 -3
- package/src/hooks/usePersistedDevicePreferences.ts +118 -0
- package/src/translations/en.json +3 -0
- package/dist/src/core/contexts/MediaDevicesContext.d.ts +0 -180
- package/dist/src/core/contexts/index.d.ts +0 -1
- package/dist/src/core/hooks/useAudioPublisher.d.ts +0 -12
- package/dist/src/core/hooks/useVideoPublisher.d.ts +0 -12
- package/dist/src/hooks/useToggleAudioMuteState.d.ts +0 -4
- package/dist/src/hooks/useToggleScreenShare.d.ts +0 -5
- package/dist/src/hooks/useToggleVideoMuteState.d.ts +0 -4
- package/src/components/Video/VideoPreview.tsx +0 -152
- package/src/core/contexts/MediaDevicesContext.tsx +0 -416
- package/src/core/contexts/index.ts +0 -1
- package/src/core/hooks/useAudioPublisher.ts +0 -146
- package/src/core/hooks/useVideoPublisher.ts +0 -177
- package/src/hooks/useToggleAudioMuteState.ts +0 -34
- package/src/hooks/useToggleScreenShare.ts +0 -43
- package/src/hooks/useToggleVideoMuteState.ts +0 -34
- /package/dist/src/components/{Video → VideoPreview}/index.d.ts +0 -0
- /package/src/components/{Video → VideoPreview}/index.ts +0 -0
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
import { useCallback, useEffect, useRef } from 'react';
|
|
2
|
-
import { map } from 'rxjs/operators';
|
|
3
|
-
import {
|
|
4
|
-
CallingState,
|
|
5
|
-
getVideoStream,
|
|
6
|
-
OwnCapability,
|
|
7
|
-
SfuModels,
|
|
8
|
-
VideoSettingsCameraFacingEnum,
|
|
9
|
-
watchForAddedDefaultVideoDevice,
|
|
10
|
-
watchForDisconnectedVideoDevice,
|
|
11
|
-
} from '@stream-io/video-client';
|
|
12
|
-
import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';
|
|
13
|
-
import { useDebugPreferredVideoCodec } from '../../components/Debug/useIsDebugMode';
|
|
14
|
-
import { useHasBrowserPermissions } from './useDevices';
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* @internal
|
|
18
|
-
*/
|
|
19
|
-
export type VideoPublisherInit = {
|
|
20
|
-
initialVideoMuted?: boolean;
|
|
21
|
-
videoDeviceId?: string;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* @internal
|
|
26
|
-
* @category Device Management
|
|
27
|
-
*/
|
|
28
|
-
export const useVideoPublisher = ({
|
|
29
|
-
initialVideoMuted,
|
|
30
|
-
videoDeviceId,
|
|
31
|
-
}: VideoPublisherInit) => {
|
|
32
|
-
const call = useCall();
|
|
33
|
-
const {
|
|
34
|
-
useCallState,
|
|
35
|
-
useCallCallingState,
|
|
36
|
-
useLocalParticipant,
|
|
37
|
-
useCallSettings,
|
|
38
|
-
} = useCallStateHooks();
|
|
39
|
-
const callState = useCallState();
|
|
40
|
-
const callingState = useCallCallingState();
|
|
41
|
-
const participant = useLocalParticipant();
|
|
42
|
-
const hasBrowserPermissionVideoInput = useHasBrowserPermissions(
|
|
43
|
-
'camera' as PermissionName,
|
|
44
|
-
);
|
|
45
|
-
const { localParticipant$ } = callState;
|
|
46
|
-
|
|
47
|
-
const preferredCodec = useDebugPreferredVideoCodec();
|
|
48
|
-
const isPublishingVideo = participant?.publishedTracks.includes(
|
|
49
|
-
SfuModels.TrackType.VIDEO,
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
const settings = useCallSettings();
|
|
53
|
-
const videoSettings = settings?.video;
|
|
54
|
-
const targetResolution = videoSettings?.target_resolution;
|
|
55
|
-
const publishVideoStream = useCallback(async () => {
|
|
56
|
-
if (!call) return;
|
|
57
|
-
if (!call.permissionsContext.hasPermission(OwnCapability.SEND_VIDEO)) {
|
|
58
|
-
throw new Error(`No permission to publish video`);
|
|
59
|
-
}
|
|
60
|
-
try {
|
|
61
|
-
const videoStream = await getVideoStream({
|
|
62
|
-
deviceId: videoDeviceId,
|
|
63
|
-
width: targetResolution?.width,
|
|
64
|
-
height: targetResolution?.height,
|
|
65
|
-
facingMode: toFacingMode(videoSettings?.camera_facing),
|
|
66
|
-
});
|
|
67
|
-
await call.publishVideoStream(videoStream, { preferredCodec });
|
|
68
|
-
} catch (e) {
|
|
69
|
-
console.log('Failed to publish video stream', e);
|
|
70
|
-
}
|
|
71
|
-
}, [
|
|
72
|
-
call,
|
|
73
|
-
preferredCodec,
|
|
74
|
-
targetResolution?.height,
|
|
75
|
-
targetResolution?.width,
|
|
76
|
-
videoDeviceId,
|
|
77
|
-
videoSettings?.camera_facing,
|
|
78
|
-
]);
|
|
79
|
-
|
|
80
|
-
const lastVideoDeviceId = useRef(videoDeviceId);
|
|
81
|
-
useEffect(() => {
|
|
82
|
-
if (
|
|
83
|
-
callingState === CallingState.JOINED &&
|
|
84
|
-
videoDeviceId !== lastVideoDeviceId.current
|
|
85
|
-
) {
|
|
86
|
-
lastVideoDeviceId.current = videoDeviceId;
|
|
87
|
-
publishVideoStream().catch((e) => {
|
|
88
|
-
console.error('Failed to publish video stream', e);
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
}, [publishVideoStream, videoDeviceId, callingState]);
|
|
92
|
-
|
|
93
|
-
const initialPublishRun = useRef(false);
|
|
94
|
-
useEffect(() => {
|
|
95
|
-
if (
|
|
96
|
-
callingState === CallingState.JOINED &&
|
|
97
|
-
!initialPublishRun.current &&
|
|
98
|
-
!initialVideoMuted
|
|
99
|
-
) {
|
|
100
|
-
// automatic publishing should happen only when joining the call
|
|
101
|
-
// from the lobby, and the video is not muted
|
|
102
|
-
publishVideoStream().catch((e) => {
|
|
103
|
-
console.error('Failed to publish video stream', e);
|
|
104
|
-
});
|
|
105
|
-
initialPublishRun.current = true;
|
|
106
|
-
}
|
|
107
|
-
}, [callingState, initialVideoMuted, publishVideoStream]);
|
|
108
|
-
|
|
109
|
-
useEffect(() => {
|
|
110
|
-
if (!localParticipant$ || !hasBrowserPermissionVideoInput) return;
|
|
111
|
-
const subscription = watchForDisconnectedVideoDevice(
|
|
112
|
-
localParticipant$.pipe(map((p) => p?.videoDeviceId)),
|
|
113
|
-
).subscribe(async () => {
|
|
114
|
-
if (!call) return;
|
|
115
|
-
call.setVideoDevice(undefined);
|
|
116
|
-
await call.stopPublish(SfuModels.TrackType.VIDEO);
|
|
117
|
-
});
|
|
118
|
-
return () => {
|
|
119
|
-
subscription.unsubscribe();
|
|
120
|
-
};
|
|
121
|
-
}, [hasBrowserPermissionVideoInput, localParticipant$, call]);
|
|
122
|
-
|
|
123
|
-
useEffect(() => {
|
|
124
|
-
if (!participant?.videoStream || !call || !isPublishingVideo) return;
|
|
125
|
-
|
|
126
|
-
const [track] = participant.videoStream.getVideoTracks();
|
|
127
|
-
const selectedVideoDeviceId = track.getSettings().deviceId;
|
|
128
|
-
|
|
129
|
-
const republishDefaultDevice = watchForAddedDefaultVideoDevice().subscribe(
|
|
130
|
-
async () => {
|
|
131
|
-
if (
|
|
132
|
-
!(
|
|
133
|
-
call &&
|
|
134
|
-
participant.videoStream &&
|
|
135
|
-
selectedVideoDeviceId === 'default'
|
|
136
|
-
)
|
|
137
|
-
)
|
|
138
|
-
return;
|
|
139
|
-
// We need to stop the original track first in order
|
|
140
|
-
// we can retrieve the new default device stream
|
|
141
|
-
track.stop();
|
|
142
|
-
const videoStream = await getVideoStream({
|
|
143
|
-
deviceId: 'default',
|
|
144
|
-
});
|
|
145
|
-
await call.publishVideoStream(videoStream);
|
|
146
|
-
},
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
const handleTrackEnded = async () => {
|
|
150
|
-
if (selectedVideoDeviceId === videoDeviceId) {
|
|
151
|
-
const videoStream = await getVideoStream({
|
|
152
|
-
deviceId: videoDeviceId,
|
|
153
|
-
});
|
|
154
|
-
await call.publishVideoStream(videoStream);
|
|
155
|
-
}
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
track.addEventListener('ended', handleTrackEnded);
|
|
159
|
-
return () => {
|
|
160
|
-
track.removeEventListener('ended', handleTrackEnded);
|
|
161
|
-
republishDefaultDevice.unsubscribe();
|
|
162
|
-
};
|
|
163
|
-
}, [videoDeviceId, call, participant?.videoStream, isPublishingVideo]);
|
|
164
|
-
|
|
165
|
-
return publishVideoStream;
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
const toFacingMode = (value: VideoSettingsCameraFacingEnum | undefined) => {
|
|
169
|
-
switch (value) {
|
|
170
|
-
case VideoSettingsCameraFacingEnum.FRONT:
|
|
171
|
-
return 'user';
|
|
172
|
-
case VideoSettingsCameraFacingEnum.BACK:
|
|
173
|
-
return 'environment';
|
|
174
|
-
default:
|
|
175
|
-
return undefined;
|
|
176
|
-
}
|
|
177
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { useCallback, useRef } from 'react';
|
|
2
|
-
import { useCallStateHooks } from '@stream-io/video-react-bindings';
|
|
3
|
-
import { OwnCapability, SfuModels } from '@stream-io/video-client';
|
|
4
|
-
|
|
5
|
-
import { useMediaDevices } from '../core';
|
|
6
|
-
import { useRequestPermission } from './useRequestPermission';
|
|
7
|
-
|
|
8
|
-
export const useToggleAudioMuteState = () => {
|
|
9
|
-
const { publishAudioStream, stopPublishingAudio } = useMediaDevices();
|
|
10
|
-
const { useLocalParticipant } = useCallStateHooks();
|
|
11
|
-
const localParticipant = useLocalParticipant();
|
|
12
|
-
|
|
13
|
-
const { isAwaitingPermission, requestPermission } = useRequestPermission(
|
|
14
|
-
OwnCapability.SEND_AUDIO,
|
|
15
|
-
);
|
|
16
|
-
|
|
17
|
-
// to keep the toggle function as stable as possible
|
|
18
|
-
const isAudioMutedReference = useRef(false);
|
|
19
|
-
|
|
20
|
-
isAudioMutedReference.current = !localParticipant?.publishedTracks.includes(
|
|
21
|
-
SfuModels.TrackType.AUDIO,
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
const toggleAudioMuteState = useCallback(async () => {
|
|
25
|
-
if (isAudioMutedReference.current) {
|
|
26
|
-
const canPublish = await requestPermission();
|
|
27
|
-
if (canPublish) return publishAudioStream();
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (!isAudioMutedReference.current) await stopPublishingAudio();
|
|
31
|
-
}, [publishAudioStream, requestPermission, stopPublishingAudio]);
|
|
32
|
-
|
|
33
|
-
return { toggleAudioMuteState, isAwaitingPermission };
|
|
34
|
-
};
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { useCallback, useRef } from 'react';
|
|
2
|
-
import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';
|
|
3
|
-
import {
|
|
4
|
-
getScreenShareStream,
|
|
5
|
-
OwnCapability,
|
|
6
|
-
SfuModels,
|
|
7
|
-
} from '@stream-io/video-client';
|
|
8
|
-
import { useRequestPermission } from './useRequestPermission';
|
|
9
|
-
|
|
10
|
-
export const useToggleScreenShare = () => {
|
|
11
|
-
const { useLocalParticipant } = useCallStateHooks();
|
|
12
|
-
const localParticipant = useLocalParticipant();
|
|
13
|
-
const call = useCall();
|
|
14
|
-
const isScreenSharingReference = useRef(false);
|
|
15
|
-
const { isAwaitingPermission, requestPermission } = useRequestPermission(
|
|
16
|
-
OwnCapability.SCREENSHARE,
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
const isScreenSharing = !!localParticipant?.publishedTracks.includes(
|
|
20
|
-
SfuModels.TrackType.SCREEN_SHARE,
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
isScreenSharingReference.current = isScreenSharing;
|
|
24
|
-
|
|
25
|
-
const toggleScreenShare = useCallback(async () => {
|
|
26
|
-
if (!isScreenSharingReference.current) {
|
|
27
|
-
const canPublish = await requestPermission();
|
|
28
|
-
if (!canPublish) return;
|
|
29
|
-
|
|
30
|
-
const stream = await getScreenShareStream().catch((e) => {
|
|
31
|
-
console.log(`Can't share screen: ${e}`);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
if (stream) {
|
|
35
|
-
return call?.publishScreenShareStream(stream);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
await call?.stopPublish(SfuModels.TrackType.SCREEN_SHARE);
|
|
40
|
-
}, [call, requestPermission]);
|
|
41
|
-
|
|
42
|
-
return { toggleScreenShare, isAwaitingPermission, isScreenSharing };
|
|
43
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { useCallback, useRef } from 'react';
|
|
2
|
-
import { useCallStateHooks } from '@stream-io/video-react-bindings';
|
|
3
|
-
import { OwnCapability, SfuModels } from '@stream-io/video-client';
|
|
4
|
-
|
|
5
|
-
import { useMediaDevices } from '../core';
|
|
6
|
-
import { useRequestPermission } from './useRequestPermission';
|
|
7
|
-
|
|
8
|
-
export const useToggleVideoMuteState = () => {
|
|
9
|
-
const { publishVideoStream, stopPublishingVideo } = useMediaDevices();
|
|
10
|
-
const { useLocalParticipant } = useCallStateHooks();
|
|
11
|
-
const localParticipant = useLocalParticipant();
|
|
12
|
-
|
|
13
|
-
const { isAwaitingPermission, requestPermission } = useRequestPermission(
|
|
14
|
-
OwnCapability.SEND_VIDEO,
|
|
15
|
-
);
|
|
16
|
-
|
|
17
|
-
// to keep the toggle function as stable as possible
|
|
18
|
-
const isVideoMutedReference = useRef(false);
|
|
19
|
-
|
|
20
|
-
isVideoMutedReference.current = !localParticipant?.publishedTracks.includes(
|
|
21
|
-
SfuModels.TrackType.VIDEO,
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
const toggleVideoMuteState = useCallback(async () => {
|
|
25
|
-
if (isVideoMutedReference.current) {
|
|
26
|
-
const canPublish = await requestPermission();
|
|
27
|
-
if (canPublish) return publishVideoStream();
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (!isVideoMutedReference.current) await stopPublishingVideo();
|
|
31
|
-
}, [publishVideoStream, requestPermission, stopPublishingVideo]);
|
|
32
|
-
|
|
33
|
-
return { toggleVideoMuteState, isAwaitingPermission };
|
|
34
|
-
};
|
|
File without changes
|
|
File without changes
|