@stream-io/video-react-native-sdk 0.0.1-alpha.141
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 +739 -0
- package/LICENSE +219 -0
- package/README.md +19 -0
- package/dist/__tests__/components/ActiveCall.test.d.ts +1 -0
- package/dist/__tests__/components/ActiveCall.test.js +89 -0
- package/dist/__tests__/components/ActiveCall.test.js.map +1 -0
- package/dist/__tests__/components/Avatar.test.d.ts +1 -0
- package/dist/__tests__/components/Avatar.test.js +34 -0
- package/dist/__tests__/components/Avatar.test.js.map +1 -0
- package/dist/__tests__/components/ParticipantView.test.d.ts +1 -0
- package/dist/__tests__/components/ParticipantView.test.js +66 -0
- package/dist/__tests__/components/ParticipantView.test.js.map +1 -0
- package/dist/__tests__/mocks/call.d.ts +2 -0
- package/dist/__tests__/mocks/call.js +21 -0
- package/dist/__tests__/mocks/call.js.map +1 -0
- package/dist/__tests__/mocks/client.d.ts +2 -0
- package/dist/__tests__/mocks/client.js +31 -0
- package/dist/__tests__/mocks/client.js.map +1 -0
- package/dist/__tests__/mocks/participant.d.ts +3 -0
- package/dist/__tests__/mocks/participant.js +25 -0
- package/dist/__tests__/mocks/participant.js.map +1 -0
- package/dist/__tests__/utils/RNTLTools.d.ts +15 -0
- package/dist/__tests__/utils/RNTLTools.js +54 -0
- package/dist/__tests__/utils/RNTLTools.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/dist/jest-setup.d.ts +1 -0
- package/dist/jest-setup.js +34 -0
- package/dist/jest-setup.js.map +1 -0
- package/dist/src/components/ActiveCall.d.ts +18 -0
- package/dist/src/components/ActiveCall.js +117 -0
- package/dist/src/components/ActiveCall.js.map +1 -0
- package/dist/src/components/Avatar.d.ts +25 -0
- package/dist/src/components/Avatar.js +55 -0
- package/dist/src/components/Avatar.js.map +1 -0
- package/dist/src/components/CallControlsButton.d.ts +22 -0
- package/dist/src/components/CallControlsButton.js +43 -0
- package/dist/src/components/CallControlsButton.js.map +1 -0
- package/dist/src/components/CallControlsView.d.ts +9 -0
- package/dist/src/components/CallControlsView.js +95 -0
- package/dist/src/components/CallControlsView.js.map +1 -0
- package/dist/src/components/CallParticipantsBadge.d.ts +1 -0
- package/dist/src/components/CallParticipantsBadge.js +48 -0
- package/dist/src/components/CallParticipantsBadge.js.map +1 -0
- package/dist/src/components/CallParticipantsInfoView.d.ts +21 -0
- package/dist/src/components/CallParticipantsInfoView.js +213 -0
- package/dist/src/components/CallParticipantsInfoView.js.map +1 -0
- package/dist/src/components/CallParticipantsList.d.ts +25 -0
- package/dist/src/components/CallParticipantsList.js +124 -0
- package/dist/src/components/CallParticipantsList.js.map +1 -0
- package/dist/src/components/CallParticipantsOptions.d.ts +8 -0
- package/dist/src/components/CallParticipantsOptions.js +189 -0
- package/dist/src/components/CallParticipantsOptions.js.map +1 -0
- package/dist/src/components/CallParticipantsSpotlightView.d.ts +1 -0
- package/dist/src/components/CallParticipantsSpotlightView.js +40 -0
- package/dist/src/components/CallParticipantsSpotlightView.js.map +1 -0
- package/dist/src/components/CallParticipantsView.d.ts +1 -0
- package/dist/src/components/CallParticipantsView.js +31 -0
- package/dist/src/components/CallParticipantsView.js.map +1 -0
- package/dist/src/components/IncomingCallView.d.ts +1 -0
- package/dist/src/components/IncomingCallView.js +98 -0
- package/dist/src/components/IncomingCallView.js.map +1 -0
- package/dist/src/components/LobbyView.d.ts +1 -0
- package/dist/src/components/LobbyView.js +215 -0
- package/dist/src/components/LobbyView.js.map +1 -0
- package/dist/src/components/LocalVideoView.d.ts +34 -0
- package/dist/src/components/LocalVideoView.js +100 -0
- package/dist/src/components/LocalVideoView.js.map +1 -0
- package/dist/src/components/NetworkQualityIndicator.d.ts +8 -0
- package/dist/src/components/NetworkQualityIndicator.js +36 -0
- package/dist/src/components/NetworkQualityIndicator.js.map +1 -0
- package/dist/src/components/OutgoingCallView.d.ts +1 -0
- package/dist/src/components/OutgoingCallView.js +103 -0
- package/dist/src/components/OutgoingCallView.js.map +1 -0
- package/dist/src/components/ParticipantReaction.d.ts +7 -0
- package/dist/src/components/ParticipantReaction.js +45 -0
- package/dist/src/components/ParticipantReaction.js.map +1 -0
- package/dist/src/components/ParticipantView.d.ts +42 -0
- package/dist/src/components/ParticipantView.js +256 -0
- package/dist/src/components/ParticipantView.js.map +1 -0
- package/dist/src/components/ReactionsModal.d.ts +7 -0
- package/dist/src/components/ReactionsModal.js +65 -0
- package/dist/src/components/ReactionsModal.js.map +1 -0
- package/dist/src/components/ToggleAudioButton.d.ts +1 -0
- package/dist/src/components/ToggleAudioButton.js +78 -0
- package/dist/src/components/ToggleAudioButton.js.map +1 -0
- package/dist/src/components/ToggleVideoButton.d.ts +1 -0
- package/dist/src/components/ToggleVideoButton.js +78 -0
- package/dist/src/components/ToggleVideoButton.js.map +1 -0
- package/dist/src/components/UserInfoView.d.ts +13 -0
- package/dist/src/components/UserInfoView.js +82 -0
- package/dist/src/components/UserInfoView.js.map +1 -0
- package/dist/src/components/VideoRenderer.d.ts +65 -0
- package/dist/src/components/VideoRenderer.js +18 -0
- package/dist/src/components/VideoRenderer.js.map +1 -0
- package/dist/src/components/index.d.ts +12 -0
- package/dist/src/components/index.js +29 -0
- package/dist/src/components/index.js.map +1 -0
- package/dist/src/constants/A11yLabels.d.ts +20 -0
- package/dist/src/constants/A11yLabels.js +29 -0
- package/dist/src/constants/A11yLabels.js.map +1 -0
- package/dist/src/constants/index.d.ts +11 -0
- package/dist/src/constants/index.js +30 -0
- package/dist/src/constants/index.js.map +1 -0
- package/dist/src/contexts/StreamVideoContext/createStoreContext.d.ts +14 -0
- package/dist/src/contexts/StreamVideoContext/createStoreContext.js +100 -0
- package/dist/src/contexts/StreamVideoContext/createStoreContext.js.map +1 -0
- package/dist/src/contexts/StreamVideoContext/index.d.ts +30 -0
- package/dist/src/contexts/StreamVideoContext/index.js +18 -0
- package/dist/src/contexts/StreamVideoContext/index.js.map +1 -0
- package/dist/src/contexts/index.d.ts +1 -0
- package/dist/src/contexts/index.js +18 -0
- package/dist/src/contexts/index.js.map +1 -0
- package/dist/src/hooks/index.d.ts +10 -0
- package/dist/src/hooks/index.js +27 -0
- package/dist/src/hooks/index.js.map +1 -0
- package/dist/src/hooks/useCallControls.d.ts +14 -0
- package/dist/src/hooks/useCallControls.js +148 -0
- package/dist/src/hooks/useCallControls.js.map +1 -0
- package/dist/src/hooks/useCallCycleEffect.d.ts +8 -0
- package/dist/src/hooks/useCallCycleEffect.js +62 -0
- package/dist/src/hooks/useCallCycleEffect.js.map +1 -0
- package/dist/src/hooks/useCallKeep.d.ts +11 -0
- package/dist/src/hooks/useCallKeep.js +41 -0
- package/dist/src/hooks/useCallKeep.js.map +1 -0
- package/dist/src/hooks/useCreateStreamVideoClient.d.ts +33 -0
- package/dist/src/hooks/useCreateStreamVideoClient.js +40 -0
- package/dist/src/hooks/useCreateStreamVideoClient.js.map +1 -0
- package/dist/src/hooks/useIncallManager.d.ts +13 -0
- package/dist/src/hooks/useIncallManager.js +24 -0
- package/dist/src/hooks/useIncallManager.js.map +1 -0
- package/dist/src/hooks/useLocalVideoStream.d.ts +7 -0
- package/dist/src/hooks/useLocalVideoStream.js +34 -0
- package/dist/src/hooks/useLocalVideoStream.js.map +1 -0
- package/dist/src/hooks/useMutingState.d.ts +12 -0
- package/dist/src/hooks/useMutingState.js +25 -0
- package/dist/src/hooks/useMutingState.js.map +1 -0
- package/dist/src/hooks/usePermissionNotification.d.ts +18 -0
- package/dist/src/hooks/usePermissionNotification.js +33 -0
- package/dist/src/hooks/usePermissionNotification.js.map +1 -0
- package/dist/src/hooks/usePermissionRequest.d.ts +1 -0
- package/dist/src/hooks/usePermissionRequest.js +62 -0
- package/dist/src/hooks/usePermissionRequest.js.map +1 -0
- package/dist/src/hooks/usePublishMediaStreams.d.ts +6 -0
- package/dist/src/hooks/usePublishMediaStreams.js +49 -0
- package/dist/src/hooks/usePublishMediaStreams.js.map +1 -0
- package/dist/src/icons/ArrowRight.d.ts +5 -0
- package/dist/src/icons/ArrowRight.js +9 -0
- package/dist/src/icons/ArrowRight.js.map +1 -0
- package/dist/src/icons/CameraSwitch.d.ts +5 -0
- package/dist/src/icons/CameraSwitch.js +9 -0
- package/dist/src/icons/CameraSwitch.js.map +1 -0
- package/dist/src/icons/Chat.d.ts +5 -0
- package/dist/src/icons/Chat.js +9 -0
- package/dist/src/icons/Chat.js.map +1 -0
- package/dist/src/icons/Cross.d.ts +5 -0
- package/dist/src/icons/Cross.js +9 -0
- package/dist/src/icons/Cross.js.map +1 -0
- package/dist/src/icons/Mic.d.ts +5 -0
- package/dist/src/icons/Mic.js +10 -0
- package/dist/src/icons/Mic.js.map +1 -0
- package/dist/src/icons/MicOff.d.ts +5 -0
- package/dist/src/icons/MicOff.js +9 -0
- package/dist/src/icons/MicOff.js.map +1 -0
- package/dist/src/icons/Participants.d.ts +5 -0
- package/dist/src/icons/Participants.js +9 -0
- package/dist/src/icons/Participants.js.map +1 -0
- package/dist/src/icons/Phone.d.ts +5 -0
- package/dist/src/icons/Phone.js +9 -0
- package/dist/src/icons/Phone.js.map +1 -0
- package/dist/src/icons/PhoneDown.d.ts +5 -0
- package/dist/src/icons/PhoneDown.js +10 -0
- package/dist/src/icons/PhoneDown.js.map +1 -0
- package/dist/src/icons/Pin.d.ts +5 -0
- package/dist/src/icons/Pin.js +9 -0
- package/dist/src/icons/Pin.js.map +1 -0
- package/dist/src/icons/Reaction.d.ts +5 -0
- package/dist/src/icons/Reaction.js +9 -0
- package/dist/src/icons/Reaction.js.map +1 -0
- package/dist/src/icons/ScreenShare.d.ts +5 -0
- package/dist/src/icons/ScreenShare.js +40 -0
- package/dist/src/icons/ScreenShare.js.map +1 -0
- package/dist/src/icons/Settings.d.ts +5 -0
- package/dist/src/icons/Settings.js +34 -0
- package/dist/src/icons/Settings.js.map +1 -0
- package/dist/src/icons/Spotlight.d.ts +5 -0
- package/dist/src/icons/Spotlight.js +9 -0
- package/dist/src/icons/Spotlight.js.map +1 -0
- package/dist/src/icons/ThreeDots.d.ts +5 -0
- package/dist/src/icons/ThreeDots.js +11 -0
- package/dist/src/icons/ThreeDots.js.map +1 -0
- package/dist/src/icons/Video.d.ts +5 -0
- package/dist/src/icons/Video.js +9 -0
- package/dist/src/icons/Video.js.map +1 -0
- package/dist/src/icons/VideoDisabled.d.ts +5 -0
- package/dist/src/icons/VideoDisabled.js +10 -0
- package/dist/src/icons/VideoDisabled.js.map +1 -0
- package/dist/src/icons/VideoOff.d.ts +5 -0
- package/dist/src/icons/VideoOff.js +10 -0
- package/dist/src/icons/VideoOff.js.map +1 -0
- package/dist/src/icons/VideoSlash.d.ts +5 -0
- package/dist/src/icons/VideoSlash.js +10 -0
- package/dist/src/icons/VideoSlash.js.map +1 -0
- package/dist/src/icons/index.d.ts +19 -0
- package/dist/src/icons/index.js +36 -0
- package/dist/src/icons/index.js.map +1 -0
- package/dist/src/providers/MediaDevices.d.ts +9 -0
- package/dist/src/providers/MediaDevices.js +43 -0
- package/dist/src/providers/MediaDevices.js.map +1 -0
- package/dist/src/providers/StreamCall.d.ts +81 -0
- package/dist/src/providers/StreamCall.js +74 -0
- package/dist/src/providers/StreamCall.js.map +1 -0
- package/dist/src/providers/StreamVideo.d.ts +10 -0
- package/dist/src/providers/StreamVideo.js +66 -0
- package/dist/src/providers/StreamVideo.js.map +1 -0
- package/dist/src/providers/index.d.ts +2 -0
- package/dist/src/providers/index.js +19 -0
- package/dist/src/providers/index.js.map +1 -0
- package/dist/src/theme/avatar.d.ts +2 -0
- package/dist/src/theme/avatar.js +11 -0
- package/dist/src/theme/avatar.js.map +1 -0
- package/dist/src/theme/button.d.ts +2 -0
- package/dist/src/theme/button.js +11 -0
- package/dist/src/theme/button.js.map +1 -0
- package/dist/src/theme/colors.d.ts +3 -0
- package/dist/src/theme/colors.js +49 -0
- package/dist/src/theme/colors.js.map +1 -0
- package/dist/src/theme/constants.d.ts +47 -0
- package/dist/src/theme/constants.js +54 -0
- package/dist/src/theme/constants.js.map +1 -0
- package/dist/src/theme/fonts.d.ts +2 -0
- package/dist/src/theme/fonts.js +67 -0
- package/dist/src/theme/fonts.js.map +1 -0
- package/dist/src/theme/icon.d.ts +2 -0
- package/dist/src/theme/icon.js +11 -0
- package/dist/src/theme/icon.js.map +1 -0
- package/dist/src/theme/index.d.ts +2 -0
- package/dist/src/theme/index.js +26 -0
- package/dist/src/theme/index.js.map +1 -0
- package/dist/src/theme/margin.d.ts +2 -0
- package/dist/src/theme/margin.js +11 -0
- package/dist/src/theme/margin.js.map +1 -0
- package/dist/src/theme/padding.d.ts +2 -0
- package/dist/src/theme/padding.js +11 -0
- package/dist/src/theme/padding.js.map +1 -0
- package/dist/src/theme/rounded.d.ts +2 -0
- package/dist/src/theme/rounded.js +11 -0
- package/dist/src/theme/rounded.js.map +1 -0
- package/dist/src/theme/spacing.d.ts +2 -0
- package/dist/src/theme/spacing.js +11 -0
- package/dist/src/theme/spacing.js.map +1 -0
- package/dist/src/theme/types.d.ts +45 -0
- package/dist/src/theme/types.js +3 -0
- package/dist/src/theme/types.js.map +1 -0
- package/dist/src/utils/StreamVideoRN.d.ts +25 -0
- package/dist/src/utils/StreamVideoRN.js +23 -0
- package/dist/src/utils/StreamVideoRN.js.map +1 -0
- package/dist/src/utils/hooks/index.d.ts +3 -0
- package/dist/src/utils/hooks/index.js +20 -0
- package/dist/src/utils/hooks/index.js.map +1 -0
- package/dist/src/utils/hooks/useAppStateListener.d.ts +1 -0
- package/dist/src/utils/hooks/useAppStateListener.js +41 -0
- package/dist/src/utils/hooks/useAppStateListener.js.map +1 -0
- package/dist/src/utils/hooks/useDebouncedValue.d.ts +7 -0
- package/dist/src/utils/hooks/useDebouncedValue.js +22 -0
- package/dist/src/utils/hooks/useDebouncedValue.js.map +1 -0
- package/dist/src/utils/hooks/usePrevious.d.ts +1 -0
- package/dist/src/utils/hooks/usePrevious.js +13 -0
- package/dist/src/utils/hooks/usePrevious.js.map +1 -0
- package/dist/src/utils/index.d.ts +5 -0
- package/dist/src/utils/index.js +53 -0
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/utils/verifyAndroidBluetoothPermissions.d.ts +1 -0
- package/dist/src/utils/verifyAndroidBluetoothPermissions.js +30 -0
- package/dist/src/utils/verifyAndroidBluetoothPermissions.js.map +1 -0
- package/index.ts +22 -0
- package/package.json +70 -0
- package/src/components/ActiveCall.tsx +122 -0
- package/src/components/Avatar.tsx +88 -0
- package/src/components/CallControlsButton.tsx +72 -0
- package/src/components/CallControlsView.tsx +128 -0
- package/src/components/CallParticipantsBadge.tsx +57 -0
- package/src/components/CallParticipantsInfoView.tsx +287 -0
- package/src/components/CallParticipantsList.tsx +172 -0
- package/src/components/CallParticipantsOptions.tsx +248 -0
- package/src/components/CallParticipantsSpotlightView.tsx +53 -0
- package/src/components/CallParticipantsView.tsx +30 -0
- package/src/components/IncomingCallView.tsx +133 -0
- package/src/components/LobbyView.tsx +236 -0
- package/src/components/LocalVideoView.tsx +141 -0
- package/src/components/NetworkQualityIndicator.tsx +72 -0
- package/src/components/OutgoingCallView.tsx +133 -0
- package/src/components/ParticipantReaction.tsx +59 -0
- package/src/components/ParticipantView.tsx +315 -0
- package/src/components/ReactionsModal.tsx +90 -0
- package/src/components/ToggleAudioButton.tsx +103 -0
- package/src/components/ToggleVideoButton.tsx +103 -0
- package/src/components/UserInfoView.tsx +118 -0
- package/src/components/VideoRenderer.tsx +85 -0
- package/src/components/index.ts +12 -0
- package/src/constants/A11yLabels.ts +24 -0
- package/src/constants/index.ts +28 -0
- package/src/contexts/StreamVideoContext/createStoreContext.tsx +117 -0
- package/src/contexts/StreamVideoContext/index.tsx +37 -0
- package/src/contexts/index.ts +1 -0
- package/src/hooks/index.ts +10 -0
- package/src/hooks/useCallControls.tsx +186 -0
- package/src/hooks/useCallCycleEffect.tsx +68 -0
- package/src/hooks/useCallKeep.tsx +51 -0
- package/src/hooks/useCreateStreamVideoClient.tsx +77 -0
- package/src/hooks/useIncallManager.tsx +23 -0
- package/src/hooks/useLocalVideoStream.ts +36 -0
- package/src/hooks/useMutingState.ts +24 -0
- package/src/hooks/usePermissionNotification.tsx +53 -0
- package/src/hooks/usePermissionRequest.tsx +67 -0
- package/src/hooks/usePublishMediaStreams.ts +59 -0
- package/src/icons/ArrowRight.tsx +16 -0
- package/src/icons/CameraSwitch.tsx +14 -0
- package/src/icons/Chat.tsx +14 -0
- package/src/icons/Cross.tsx +14 -0
- package/src/icons/Mic.tsx +18 -0
- package/src/icons/MicOff.tsx +14 -0
- package/src/icons/Participants.tsx +16 -0
- package/src/icons/Phone.tsx +14 -0
- package/src/icons/PhoneDown.tsx +15 -0
- package/src/icons/Pin.tsx +16 -0
- package/src/icons/Reaction.tsx +14 -0
- package/src/icons/ScreenShare.tsx +32 -0
- package/src/icons/Settings.tsx +13 -0
- package/src/icons/Spotlight.tsx +16 -0
- package/src/icons/ThreeDots.tsx +13 -0
- package/src/icons/Video.tsx +14 -0
- package/src/icons/VideoDisabled.tsx +22 -0
- package/src/icons/VideoOff.tsx +20 -0
- package/src/icons/VideoSlash.tsx +15 -0
- package/src/icons/index.tsx +19 -0
- package/src/providers/MediaDevices.tsx +45 -0
- package/src/providers/StreamCall.tsx +136 -0
- package/src/providers/StreamVideo.tsx +50 -0
- package/src/providers/index.ts +2 -0
- package/src/theme/avatar.ts +9 -0
- package/src/theme/button.ts +9 -0
- package/src/theme/colors.ts +49 -0
- package/src/theme/constants.ts +51 -0
- package/src/theme/fonts.ts +65 -0
- package/src/theme/icon.ts +9 -0
- package/src/theme/index.ts +25 -0
- package/src/theme/margin.ts +9 -0
- package/src/theme/padding.ts +9 -0
- package/src/theme/rounded.ts +9 -0
- package/src/theme/spacing.ts +9 -0
- package/src/theme/types.ts +64 -0
- package/src/utils/StreamVideoRN.ts +35 -0
- package/src/utils/hooks/index.ts +3 -0
- package/src/utils/hooks/useAppStateListener.ts +48 -0
- package/src/utils/hooks/useDebouncedValue.ts +21 -0
- package/src/utils/hooks/usePrevious.ts +11 -0
- package/src/utils/index.ts +45 -0
- package/src/utils/verifyAndroidBluetoothPermissions.ts +31 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CallingState,
|
|
3
|
+
getAudioStream,
|
|
4
|
+
getVideoStream,
|
|
5
|
+
SfuModels,
|
|
6
|
+
Call,
|
|
7
|
+
} from '@stream-io/video-client';
|
|
8
|
+
import { useCall, useLocalParticipant } from '@stream-io/video-react-bindings';
|
|
9
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
10
|
+
import {
|
|
11
|
+
useStreamVideoStoreSetState,
|
|
12
|
+
useStreamVideoStoreValue,
|
|
13
|
+
} from '../contexts';
|
|
14
|
+
import { useAppStateListener } from '../utils/hooks/useAppStateListener';
|
|
15
|
+
import NetInfo from '@react-native-community/netinfo';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A helper hook which exposes audio, video mute and camera facing mode and
|
|
19
|
+
* their respective functions to toggle state
|
|
20
|
+
*
|
|
21
|
+
* @category Device Management
|
|
22
|
+
*/
|
|
23
|
+
export const useCallControls = () => {
|
|
24
|
+
const localParticipant = useLocalParticipant();
|
|
25
|
+
const call = useCall();
|
|
26
|
+
/** Refs to keep track of the current call and whether the user is online or not */
|
|
27
|
+
const callRef = useRef(call);
|
|
28
|
+
callRef.current = call;
|
|
29
|
+
const isOnlineRef = useRef(true);
|
|
30
|
+
|
|
31
|
+
const setState = useStreamVideoStoreSetState();
|
|
32
|
+
const isCameraOnFrontFacingMode = useStreamVideoStoreValue(
|
|
33
|
+
(store) => store.isCameraOnFrontFacingMode,
|
|
34
|
+
);
|
|
35
|
+
const currentAudioDevice = useStreamVideoStoreValue(
|
|
36
|
+
(store) => store.currentAudioDevice,
|
|
37
|
+
);
|
|
38
|
+
const videoDevices = useStreamVideoStoreValue((store) => store.videoDevices);
|
|
39
|
+
const currentVideoDevice = useStreamVideoStoreValue(
|
|
40
|
+
(store) => store.currentVideoDevice,
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const publishAudioStream = useCallback(async () => {
|
|
44
|
+
try {
|
|
45
|
+
// Client picks up the default audio stream.
|
|
46
|
+
// For mobile devices there will always be one audio input
|
|
47
|
+
if (currentAudioDevice && isOnlineRef.current) {
|
|
48
|
+
const audioStream = await getAudioStream(currentAudioDevice.deviceId);
|
|
49
|
+
if (call) {
|
|
50
|
+
await call.publishAudioStream(audioStream);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
} catch (e) {
|
|
54
|
+
console.log('Failed to publish audio stream', e);
|
|
55
|
+
}
|
|
56
|
+
}, [currentAudioDevice, call]);
|
|
57
|
+
|
|
58
|
+
const publishVideoStream = useCallback(async () => {
|
|
59
|
+
try {
|
|
60
|
+
if (currentVideoDevice && isOnlineRef.current) {
|
|
61
|
+
const videoStream = await getVideoStream(currentVideoDevice.deviceId);
|
|
62
|
+
if (call) {
|
|
63
|
+
await call.publishVideoStream(videoStream);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
} catch (e) {
|
|
67
|
+
console.log('Failed to publish video stream', e);
|
|
68
|
+
}
|
|
69
|
+
}, [call, currentVideoDevice]);
|
|
70
|
+
|
|
71
|
+
const isAudioPublished = localParticipant?.publishedTracks.includes(
|
|
72
|
+
SfuModels.TrackType.AUDIO,
|
|
73
|
+
);
|
|
74
|
+
const isVideoPublished = localParticipant?.publishedTracks.includes(
|
|
75
|
+
SfuModels.TrackType.VIDEO,
|
|
76
|
+
);
|
|
77
|
+
/** Refs to keep track of whether the user has published the track before going offline */
|
|
78
|
+
const isAudioPublishedRef = useRef(false);
|
|
79
|
+
const isVideoPublishedRef = useRef(false);
|
|
80
|
+
isAudioPublishedRef.current = !isAudioPublished;
|
|
81
|
+
isVideoPublishedRef.current = !isVideoPublished;
|
|
82
|
+
|
|
83
|
+
/** Refs to be used for useEffect that does the rejoining flow when coming back offline */
|
|
84
|
+
const publishAudioStreamRef = useRef(publishAudioStream);
|
|
85
|
+
const publishVideoStreamRef = useRef(publishVideoStream);
|
|
86
|
+
publishAudioStreamRef.current = publishAudioStream;
|
|
87
|
+
publishVideoStreamRef.current = publishVideoStream;
|
|
88
|
+
|
|
89
|
+
/** Attempt to republish video stream when app comes back to foreground */
|
|
90
|
+
useAppStateListener(
|
|
91
|
+
isVideoPublishedRef.current ? publishVideoStream : undefined,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Effect to re-join to an existing call happens in case the user comes back online
|
|
96
|
+
*/
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
const unsubscribe = NetInfo.addEventListener(async (state) => {
|
|
99
|
+
const { isConnected, isInternetReachable } = state;
|
|
100
|
+
const isOnline = isConnected !== false && isInternetReachable !== false;
|
|
101
|
+
isOnlineRef.current = isOnline;
|
|
102
|
+
if (!callRef.current) return;
|
|
103
|
+
const callToJoin = callRef.current;
|
|
104
|
+
await rejoinCall(
|
|
105
|
+
callToJoin,
|
|
106
|
+
isOnline,
|
|
107
|
+
isAudioPublishedRef.current,
|
|
108
|
+
isVideoPublishedRef.current,
|
|
109
|
+
publishAudioStreamRef.current,
|
|
110
|
+
publishVideoStreamRef.current,
|
|
111
|
+
);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
return unsubscribe;
|
|
115
|
+
}, []);
|
|
116
|
+
|
|
117
|
+
const toggleVideoMuted = useCallback(async () => {
|
|
118
|
+
if (!isVideoPublished) {
|
|
119
|
+
publishVideoStream();
|
|
120
|
+
} else {
|
|
121
|
+
await call?.stopPublish(SfuModels.TrackType.VIDEO);
|
|
122
|
+
}
|
|
123
|
+
}, [call, isVideoPublished, publishVideoStream]);
|
|
124
|
+
|
|
125
|
+
const toggleAudioMuted = useCallback(async () => {
|
|
126
|
+
if (!isAudioPublished) {
|
|
127
|
+
publishAudioStream();
|
|
128
|
+
} else {
|
|
129
|
+
await call?.stopPublish(SfuModels.TrackType.AUDIO);
|
|
130
|
+
}
|
|
131
|
+
}, [call, isAudioPublished, publishAudioStream]);
|
|
132
|
+
|
|
133
|
+
const toggleCameraFacingMode = useCallback(() => {
|
|
134
|
+
const videoDevice = videoDevices.find(
|
|
135
|
+
(device) =>
|
|
136
|
+
device.kind === 'videoinput' &&
|
|
137
|
+
(!isCameraOnFrontFacingMode
|
|
138
|
+
? device.facing === 'front'
|
|
139
|
+
: device.facing === 'environment'),
|
|
140
|
+
);
|
|
141
|
+
setState((prevState) => ({
|
|
142
|
+
currentVideoDevice: videoDevice,
|
|
143
|
+
isCameraOnFrontFacingMode: !prevState.isCameraOnFrontFacingMode,
|
|
144
|
+
}));
|
|
145
|
+
}, [isCameraOnFrontFacingMode, videoDevices, setState]);
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
isAudioPublished,
|
|
149
|
+
isVideoPublished,
|
|
150
|
+
isCameraOnFrontFacingMode,
|
|
151
|
+
toggleAudioMuted,
|
|
152
|
+
toggleVideoMuted,
|
|
153
|
+
toggleCameraFacingMode,
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Helper function to rejoin a call and then publish the streams
|
|
159
|
+
*/
|
|
160
|
+
async function rejoinCall(
|
|
161
|
+
callToJoin: Call,
|
|
162
|
+
isOnline: boolean,
|
|
163
|
+
isAudioPublished: boolean,
|
|
164
|
+
isVideoPublished: boolean,
|
|
165
|
+
publishAudioStream: () => Promise<void>,
|
|
166
|
+
publishVideoStream: () => Promise<void>,
|
|
167
|
+
) {
|
|
168
|
+
const isCurrentStateOffline =
|
|
169
|
+
callToJoin.state.callingState === CallingState.OFFLINE;
|
|
170
|
+
if (!isOnline && !isCurrentStateOffline) {
|
|
171
|
+
callToJoin.state.setCallingState(CallingState.OFFLINE);
|
|
172
|
+
} else if (isOnline && isCurrentStateOffline && callToJoin.rejoin) {
|
|
173
|
+
try {
|
|
174
|
+
await callToJoin.rejoin();
|
|
175
|
+
if (isAudioPublished) {
|
|
176
|
+
await publishAudioStream();
|
|
177
|
+
}
|
|
178
|
+
if (isVideoPublished) {
|
|
179
|
+
await publishVideoStream();
|
|
180
|
+
}
|
|
181
|
+
} catch (e) {
|
|
182
|
+
console.error('Failed to rejoin', e);
|
|
183
|
+
callToJoin.state.setCallingState(CallingState.RECONNECTING_FAILED);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { useCall, useCallCallingState } from '@stream-io/video-react-bindings';
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
|
+
import { CallingState } from '@stream-io/video-client';
|
|
4
|
+
import { CallCycleHandlersType } from '../providers';
|
|
5
|
+
import { usePrevious } from '../utils/hooks/usePrevious';
|
|
6
|
+
|
|
7
|
+
const NON_ACTIVE_CALLING_STATES = [CallingState.UNKNOWN, CallingState.IDLE];
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* @param callCycleHandlers
|
|
11
|
+
*
|
|
12
|
+
* @category Client State
|
|
13
|
+
*/
|
|
14
|
+
export const useCallCycleEffect = (
|
|
15
|
+
callCycleHandlers: CallCycleHandlersType,
|
|
16
|
+
) => {
|
|
17
|
+
const call = useCall();
|
|
18
|
+
const callingState = useCallCallingState();
|
|
19
|
+
const prevCallingState = usePrevious(callingState);
|
|
20
|
+
const {
|
|
21
|
+
onCallJoined,
|
|
22
|
+
onCallIncoming,
|
|
23
|
+
onCallOutgoing,
|
|
24
|
+
onCallHungUp,
|
|
25
|
+
onCallRejected,
|
|
26
|
+
onCallJoining,
|
|
27
|
+
} = callCycleHandlers;
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (!call || NON_ACTIVE_CALLING_STATES.includes(callingState)) return;
|
|
31
|
+
const isCallCreatedByMe = call.data?.created_by.id === call?.currentUserId;
|
|
32
|
+
const isCallCreatedByOther =
|
|
33
|
+
!!call.data?.created_by.id && !isCallCreatedByMe;
|
|
34
|
+
const isIncomingCall =
|
|
35
|
+
callingState === CallingState.RINGING &&
|
|
36
|
+
!isCallCreatedByMe &&
|
|
37
|
+
onCallIncoming;
|
|
38
|
+
const isOutgoingCall =
|
|
39
|
+
callingState === CallingState.RINGING &&
|
|
40
|
+
isCallCreatedByMe &&
|
|
41
|
+
onCallOutgoing;
|
|
42
|
+
const isActiveCall = callingState === CallingState.JOINED && onCallJoined;
|
|
43
|
+
const isCallHungUp = callingState === CallingState.LEFT && onCallHungUp;
|
|
44
|
+
const isCallRejected =
|
|
45
|
+
callingState === CallingState.LEFT &&
|
|
46
|
+
isCallCreatedByOther &&
|
|
47
|
+
onCallRejected;
|
|
48
|
+
const isCallJoining =
|
|
49
|
+
callingState === CallingState.JOINING && onCallJoining;
|
|
50
|
+
|
|
51
|
+
if (isIncomingCall) return onCallIncoming();
|
|
52
|
+
if (isOutgoingCall) return onCallOutgoing();
|
|
53
|
+
if (isActiveCall) return onCallJoined();
|
|
54
|
+
if (isCallHungUp) return onCallHungUp();
|
|
55
|
+
if (isCallRejected) return onCallRejected();
|
|
56
|
+
if (isCallJoining) return onCallJoining();
|
|
57
|
+
}, [
|
|
58
|
+
callingState,
|
|
59
|
+
prevCallingState,
|
|
60
|
+
call,
|
|
61
|
+
onCallIncoming,
|
|
62
|
+
onCallOutgoing,
|
|
63
|
+
onCallJoined,
|
|
64
|
+
onCallHungUp,
|
|
65
|
+
onCallRejected,
|
|
66
|
+
onCallJoining,
|
|
67
|
+
]);
|
|
68
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { useCallback, useMemo } from 'react';
|
|
2
|
+
import { Platform } from 'react-native';
|
|
3
|
+
import { generateCallTitle } from '../utils';
|
|
4
|
+
import { useCall } from '@stream-io/video-react-bindings';
|
|
5
|
+
|
|
6
|
+
type RNCallKeepType = typeof import('react-native-callkeep').default;
|
|
7
|
+
|
|
8
|
+
let RNCallKeep: RNCallKeepType | undefined;
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
RNCallKeep = require('react-native-callkeep').default;
|
|
12
|
+
} catch (e) {}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
* @returns
|
|
17
|
+
*
|
|
18
|
+
* @category Call Operations
|
|
19
|
+
*
|
|
20
|
+
*/
|
|
21
|
+
export const useCallKeep = () => {
|
|
22
|
+
const activeCall = useCall();
|
|
23
|
+
if (!RNCallKeep) {
|
|
24
|
+
throw Error(
|
|
25
|
+
"react-native-callkeep library is not installed. Please install it using 'yarn add react-native-callkeep' or 'npm install react-native-callkeep'",
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const users = activeCall?.state.getCurrentValue(activeCall.state.members$);
|
|
30
|
+
const userIds = useMemo(() => Object.keys(users || {}), [users]);
|
|
31
|
+
const callTitle = generateCallTitle(userIds);
|
|
32
|
+
|
|
33
|
+
const startCall = useCallback(async () => {
|
|
34
|
+
if (Platform.OS === 'ios' && activeCall) {
|
|
35
|
+
await RNCallKeep?.startCall(
|
|
36
|
+
activeCall.id,
|
|
37
|
+
callTitle,
|
|
38
|
+
userIds.join(','),
|
|
39
|
+
'generic',
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
}, [activeCall, callTitle, userIds]);
|
|
43
|
+
|
|
44
|
+
const endCall = useCallback(async () => {
|
|
45
|
+
if (Platform.OS === 'ios' && activeCall) {
|
|
46
|
+
await RNCallKeep?.endCall(activeCall.id);
|
|
47
|
+
}
|
|
48
|
+
}, [activeCall]);
|
|
49
|
+
|
|
50
|
+
return { startCall, endCall };
|
|
51
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {
|
|
2
|
+
StreamClientOptions,
|
|
3
|
+
StreamVideoClient,
|
|
4
|
+
TokenOrProvider,
|
|
5
|
+
User,
|
|
6
|
+
} from '@stream-io/video-client';
|
|
7
|
+
import { useEffect, useRef, useState } from 'react';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Exclude types from documentation site, but we should still add doc comments
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
export type StreamVideoClientInit = {
|
|
14
|
+
/**
|
|
15
|
+
* The Stream API key.
|
|
16
|
+
*/
|
|
17
|
+
apiKey: string;
|
|
18
|
+
/**
|
|
19
|
+
* The token or token provider.
|
|
20
|
+
*/
|
|
21
|
+
tokenOrProvider: TokenOrProvider;
|
|
22
|
+
/**
|
|
23
|
+
* The client options.
|
|
24
|
+
*/
|
|
25
|
+
options?: StreamClientOptions;
|
|
26
|
+
/**
|
|
27
|
+
* The user to connect.
|
|
28
|
+
*/
|
|
29
|
+
user: User;
|
|
30
|
+
/**
|
|
31
|
+
* Whether the user is anonymous. Defaults to `false`.
|
|
32
|
+
*/
|
|
33
|
+
isAnonymous?: boolean;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Creates a new `StreamVideoClient` instance and connects the given user.
|
|
38
|
+
*
|
|
39
|
+
* @category Client State
|
|
40
|
+
*/
|
|
41
|
+
export const useCreateStreamVideoClient = ({
|
|
42
|
+
apiKey,
|
|
43
|
+
tokenOrProvider,
|
|
44
|
+
user,
|
|
45
|
+
options,
|
|
46
|
+
isAnonymous = false,
|
|
47
|
+
}: StreamVideoClientInit) => {
|
|
48
|
+
const [client] = useState(() => new StreamVideoClient(apiKey, options));
|
|
49
|
+
|
|
50
|
+
const disconnectRef = useRef(Promise.resolve());
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
const connectionPromise = disconnectRef.current.then(() => {
|
|
53
|
+
if (isAnonymous) {
|
|
54
|
+
return client
|
|
55
|
+
.connectAnonymousUser(user, tokenOrProvider)
|
|
56
|
+
.catch((err) => {
|
|
57
|
+
console.error(`Failed to establish connection`, err);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return client.connectUser(user, tokenOrProvider).catch((err) => {
|
|
61
|
+
console.error(`Failed to establish connection`, err);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
return () => {
|
|
66
|
+
disconnectRef.current = connectionPromise
|
|
67
|
+
.then(() => client.disconnectUser())
|
|
68
|
+
.catch((err) => {
|
|
69
|
+
console.error(`Failed to disconnect`, err);
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
// we want to re-run this effect only in some special cases
|
|
73
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
74
|
+
}, [apiKey, tokenOrProvider, client, isAnonymous, user?.id]);
|
|
75
|
+
|
|
76
|
+
return client;
|
|
77
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import InCallManager from 'react-native-incall-manager';
|
|
3
|
+
|
|
4
|
+
export type IncallManagerProps = {
|
|
5
|
+
media: 'audio' | 'video';
|
|
6
|
+
auto: boolean;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A hook to handle IncallManager specs in the application.
|
|
11
|
+
*
|
|
12
|
+
* @param media
|
|
13
|
+
* @param auto
|
|
14
|
+
*
|
|
15
|
+
* @category Device Management
|
|
16
|
+
* */
|
|
17
|
+
export const useIncallManager = ({ auto, media }: IncallManagerProps) => {
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
InCallManager.start({ media, auto });
|
|
20
|
+
|
|
21
|
+
return () => InCallManager.stop();
|
|
22
|
+
}, [auto, media]);
|
|
23
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { disposeOfMediaStream, getVideoStream } from '@stream-io/video-client';
|
|
3
|
+
import { MediaStream } from 'react-native-webrtc';
|
|
4
|
+
import { useStreamVideoStoreValue } from '../contexts';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A hook which provides the device's local video stream.
|
|
8
|
+
*
|
|
9
|
+
* @category Device Management
|
|
10
|
+
*/
|
|
11
|
+
export const useLocalVideoStream = () => {
|
|
12
|
+
const [videoStream, setVideoStream] = useState<MediaStream | undefined>(
|
|
13
|
+
undefined,
|
|
14
|
+
);
|
|
15
|
+
const currentVideoDevice = useStreamVideoStoreValue(
|
|
16
|
+
(store) => store.currentVideoDevice,
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
const loadVideoStream = async () => {
|
|
21
|
+
// If there is no video device, we don't need to load a video stream.
|
|
22
|
+
if (!currentVideoDevice?.deviceId) return null;
|
|
23
|
+
|
|
24
|
+
const stream = await getVideoStream({
|
|
25
|
+
deviceId: currentVideoDevice.deviceId,
|
|
26
|
+
});
|
|
27
|
+
setVideoStream((previousStream) => {
|
|
28
|
+
if (previousStream) disposeOfMediaStream(previousStream);
|
|
29
|
+
return stream;
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
loadVideoStream();
|
|
33
|
+
}, [currentVideoDevice?.deviceId]);
|
|
34
|
+
|
|
35
|
+
return videoStream;
|
|
36
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useStreamVideoStoreSetState,
|
|
3
|
+
useStreamVideoStoreValue,
|
|
4
|
+
} from '../contexts/StreamVideoContext';
|
|
5
|
+
/**
|
|
6
|
+
* A helper hook which exposes audio, video mute and camera facing mode and
|
|
7
|
+
* their respective functions to toggle state
|
|
8
|
+
*
|
|
9
|
+
* @category Device Management
|
|
10
|
+
*/
|
|
11
|
+
export const useMutingState = () => {
|
|
12
|
+
const isAudioMuted = useStreamVideoStoreValue((store) => store.isAudioMuted);
|
|
13
|
+
const isVideoMuted = useStreamVideoStoreValue((store) => store.isVideoMuted);
|
|
14
|
+
const setState = useStreamVideoStoreSetState();
|
|
15
|
+
const toggleAudioState = () => setState({ isAudioMuted: !isAudioMuted });
|
|
16
|
+
const toggleVideoState = () => setState({ isVideoMuted: !isVideoMuted });
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
isAudioMuted,
|
|
20
|
+
isVideoMuted,
|
|
21
|
+
toggleAudioState,
|
|
22
|
+
toggleVideoState,
|
|
23
|
+
};
|
|
24
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { OwnCapability } from '@stream-io/video-client';
|
|
2
|
+
import { useHasPermissions } from '@stream-io/video-react-bindings';
|
|
3
|
+
import { useCallback, useEffect } from 'react';
|
|
4
|
+
import { Alert } from 'react-native';
|
|
5
|
+
import { usePrevious } from '../utils/hooks/usePrevious';
|
|
6
|
+
|
|
7
|
+
export type PermissionNotificationProps = {
|
|
8
|
+
/**
|
|
9
|
+
* The permission to check for.
|
|
10
|
+
*/
|
|
11
|
+
permission: OwnCapability;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The message to display in the notification once
|
|
15
|
+
* the requested permission is granted.
|
|
16
|
+
*/
|
|
17
|
+
messageApproved: string;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The message to display in the notification once a permission
|
|
21
|
+
* is revoked.
|
|
22
|
+
*/
|
|
23
|
+
messageRevoked: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const usePermissionNotification = (
|
|
27
|
+
props: PermissionNotificationProps,
|
|
28
|
+
) => {
|
|
29
|
+
const { permission, messageApproved, messageRevoked } = props;
|
|
30
|
+
const hasPermission = useHasPermissions(permission);
|
|
31
|
+
const previousHasPermission = usePrevious(hasPermission);
|
|
32
|
+
|
|
33
|
+
const showGrantedNotification = useCallback(() => {
|
|
34
|
+
Alert.alert(messageApproved);
|
|
35
|
+
}, [messageApproved]);
|
|
36
|
+
|
|
37
|
+
const showRevokedNotification = useCallback(() => {
|
|
38
|
+
Alert.alert(messageRevoked);
|
|
39
|
+
}, [messageRevoked]);
|
|
40
|
+
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (hasPermission && !previousHasPermission) {
|
|
43
|
+
showGrantedNotification();
|
|
44
|
+
} else if (!hasPermission && previousHasPermission) {
|
|
45
|
+
showRevokedNotification();
|
|
46
|
+
}
|
|
47
|
+
}, [
|
|
48
|
+
hasPermission,
|
|
49
|
+
previousHasPermission,
|
|
50
|
+
showGrantedNotification,
|
|
51
|
+
showRevokedNotification,
|
|
52
|
+
]);
|
|
53
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { OwnCapability, PermissionRequestEvent } from '@stream-io/video-client';
|
|
2
|
+
import { useCall, useHasPermissions } from '@stream-io/video-react-bindings';
|
|
3
|
+
import { useCallback, useEffect } from 'react';
|
|
4
|
+
import { Alert } from 'react-native';
|
|
5
|
+
|
|
6
|
+
export const usePermissionRequest = () => {
|
|
7
|
+
const call = useCall();
|
|
8
|
+
|
|
9
|
+
const userHasUpdateCallPermissionsCapability = useHasPermissions(
|
|
10
|
+
OwnCapability.UPDATE_CALL_PERMISSIONS,
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
const messageForPermission = (userName: string, permission: string) => {
|
|
14
|
+
switch (permission) {
|
|
15
|
+
case OwnCapability.SEND_AUDIO:
|
|
16
|
+
return `${userName} is requesting to speak`;
|
|
17
|
+
case OwnCapability.SEND_VIDEO:
|
|
18
|
+
return `${userName} is requesting to share their camera`;
|
|
19
|
+
case OwnCapability.SCREENSHARE:
|
|
20
|
+
return `${userName} is requesting to present their screen`;
|
|
21
|
+
default:
|
|
22
|
+
return `${userName} is requesting permission: ${permission}`;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const handleUpdatePermission = useCallback(
|
|
27
|
+
(request: PermissionRequestEvent, allow: boolean) => {
|
|
28
|
+
return async () => {
|
|
29
|
+
const { user, permissions } = request;
|
|
30
|
+
try {
|
|
31
|
+
if (allow) {
|
|
32
|
+
await call?.grantPermissions(user.id, permissions);
|
|
33
|
+
} else {
|
|
34
|
+
await call?.revokePermissions(user.id, permissions);
|
|
35
|
+
}
|
|
36
|
+
} catch (err) {
|
|
37
|
+
console.log(err);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
[call],
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (!call || !userHasUpdateCallPermissionsCapability) return;
|
|
46
|
+
return call.on('call.permission_request', (event) => {
|
|
47
|
+
if (event.type !== 'call.permission_request') return;
|
|
48
|
+
const { user, permissions } = event;
|
|
49
|
+
permissions.forEach((permission) => {
|
|
50
|
+
return Alert.alert(
|
|
51
|
+
'Permissions Request',
|
|
52
|
+
messageForPermission(user.name ?? user.id, permission),
|
|
53
|
+
[
|
|
54
|
+
{
|
|
55
|
+
text: 'Reject',
|
|
56
|
+
onPress: handleUpdatePermission(event, false),
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
text: 'Allow',
|
|
60
|
+
onPress: handleUpdatePermission(event, true),
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
}, [call, userHasUpdateCallPermissionsCapability, handleUpdatePermission]);
|
|
67
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { useCall } from '@stream-io/video-react-bindings';
|
|
2
|
+
import { useStreamVideoStoreValue } from '../contexts/StreamVideoContext';
|
|
3
|
+
import {
|
|
4
|
+
OwnCapability,
|
|
5
|
+
getAudioStream,
|
|
6
|
+
getVideoStream,
|
|
7
|
+
} from '@stream-io/video-client';
|
|
8
|
+
import { useEffect } from 'react';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A helper hook that takes care of publishing audio and video streams of the active call.
|
|
12
|
+
*
|
|
13
|
+
* @category Device Management
|
|
14
|
+
*/
|
|
15
|
+
export const usePublishMediaStreams = () => {
|
|
16
|
+
const activeCall = useCall();
|
|
17
|
+
const currentAudioDevice = useStreamVideoStoreValue(
|
|
18
|
+
(store) => store.currentAudioDevice,
|
|
19
|
+
);
|
|
20
|
+
const currentVideoDevice = useStreamVideoStoreValue(
|
|
21
|
+
(store) => store.currentVideoDevice,
|
|
22
|
+
);
|
|
23
|
+
const isVideoMuted = useStreamVideoStoreValue((store) => store.isVideoMuted);
|
|
24
|
+
const isAudioMuted = useStreamVideoStoreValue((store) => store.isAudioMuted);
|
|
25
|
+
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (
|
|
28
|
+
!activeCall?.permissionsContext.hasPermission(OwnCapability.SEND_AUDIO)
|
|
29
|
+
) {
|
|
30
|
+
console.log(`No permission to publish audio`);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (currentAudioDevice && !isAudioMuted) {
|
|
34
|
+
getAudioStream(currentAudioDevice.deviceId)
|
|
35
|
+
.then((stream) => activeCall?.publishAudioStream(stream))
|
|
36
|
+
.catch((error) => {
|
|
37
|
+
console.log(error);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}, [activeCall, currentAudioDevice, isAudioMuted]);
|
|
41
|
+
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (
|
|
44
|
+
!activeCall?.permissionsContext.hasPermission(OwnCapability.SEND_VIDEO)
|
|
45
|
+
) {
|
|
46
|
+
console.log(`No permission to publish video`);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (currentVideoDevice && !isVideoMuted) {
|
|
50
|
+
getVideoStream(currentVideoDevice.deviceId)
|
|
51
|
+
.then((stream) => {
|
|
52
|
+
activeCall?.publishVideoStream(stream);
|
|
53
|
+
})
|
|
54
|
+
.catch((error) => {
|
|
55
|
+
console.log(error);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}, [activeCall, currentVideoDevice, isVideoMuted]);
|
|
59
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Svg, Path } from 'react-native-svg';
|
|
2
|
+
|
|
3
|
+
type Props = {
|
|
4
|
+
color: string;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const ArrowRight = ({ color }: Props) => (
|
|
8
|
+
<Svg viewBox="0 0 8 15">
|
|
9
|
+
<Path
|
|
10
|
+
clipRule="evenodd"
|
|
11
|
+
fillRule="evenodd"
|
|
12
|
+
d="M 0.553016 2.50028 L 5.3299 7.5 L 0.553016 12.4997 C 0.111957 12.9585 0.111957 13.6972 0.553016 14.1559 C 0.994074 14.6147 1.71173 14.6147 2.14531 14.1559 L 7.66975 8.37864 C 7.9015 8.1376 8.01363 7.8188 7.99868 7.5 C 8.01363 7.1812 7.9015 6.8624 7.66975 6.62136 L 2.14531 0.84407 C 1.70425 0.385308 0.986598 0.385308 0.553016 0.84407 C 0.111957 1.30283 0.111957 2.04152 0.553016 2.50028 Z"
|
|
13
|
+
fill={color}
|
|
14
|
+
/>
|
|
15
|
+
</Svg>
|
|
16
|
+
);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Svg, Path } from 'react-native-svg';
|
|
2
|
+
|
|
3
|
+
type Props = {
|
|
4
|
+
color: string;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const CameraSwitch = ({ color }: Props) => (
|
|
8
|
+
<Svg viewBox="0 0 28 23">
|
|
9
|
+
<Path
|
|
10
|
+
d="M3.86621 22.0075H24.1117C26.5225 22.0075 27.7948 20.7575 27.7948 18.3691V6.65036C27.7948 4.26196 26.5225 3.01196 24.1117 3.01196H21.143C20.2725 3.01196 19.9934 2.86687 19.4466 2.29768L18.5649 1.34902C17.9845 0.735177 17.393 0.433838 16.2546 0.433838H11.6675C10.5292 0.433838 9.93764 0.735177 9.35728 1.34902L8.47558 2.29768C7.93987 2.85571 7.64969 3.01196 6.77916 3.01196H3.86621C1.4555 3.01196 0.194336 4.26196 0.194336 6.65036V18.3691C0.194336 20.7575 1.4555 22.0075 3.86621 22.0075ZM10.0492 8.34678C9.66978 7.90036 9.80371 7.29768 10.3729 6.86241C11.3104 6.11464 12.6274 5.65705 13.989 5.65705C17.1363 5.65705 19.614 7.75527 20.1609 10.7798H21.21C21.768 10.7798 21.9131 11.3155 21.5894 11.762L19.7925 14.2508C19.4689 14.7084 18.9109 14.6861 18.5872 14.2508L16.7792 11.762C16.4443 11.3267 16.6006 10.7798 17.1586 10.7798H18.2747C17.7725 8.9383 16.0649 7.57669 13.989 7.57669C13.0068 7.57669 12.2479 7.87803 11.489 8.46955C10.9756 8.82669 10.4399 8.80437 10.0492 8.34678ZM6.36621 11.9517L8.15192 9.47402C8.48675 9.01643 9.03362 9.03875 9.35728 9.47402L11.1765 11.9517C11.5001 12.387 11.3439 12.9338 10.7859 12.9338H9.72558C10.2278 14.7754 11.9354 16.137 14.0113 16.137C14.9934 16.137 15.7524 15.8356 16.5113 15.2553C17.0247 14.887 17.5716 14.9204 17.951 15.3669C18.3305 15.8133 18.2077 16.4383 17.6274 16.8624C16.6899 17.6102 15.3841 18.0566 14.0113 18.0566C10.8751 18.0566 8.3863 15.9584 7.83942 12.9338H6.74567C6.18764 12.9338 6.04255 12.3981 6.36621 11.9517Z"
|
|
11
|
+
fill={color}
|
|
12
|
+
/>
|
|
13
|
+
</Svg>
|
|
14
|
+
);
|