diff --git a/packages/react-native-sdk/src/components/Call/CallControls/ToggleAudioPreviewButton.tsx b/packages/react-native-sdk/src/components/Call/CallControls/ToggleAudioPreviewButton.tsx index b7ca63244c..144cd41a8b 100644 --- a/packages/react-native-sdk/src/components/Call/CallControls/ToggleAudioPreviewButton.tsx +++ b/packages/react-native-sdk/src/components/Call/CallControls/ToggleAudioPreviewButton.tsx @@ -1,8 +1,7 @@ -import { useCallStateHooks } from '@stream-io/video-react-bindings'; +import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings'; import React from 'react'; import { useTheme } from '../../../contexts'; import { Mic, MicOff } from '../../../icons'; -import { useMediaStreamManagement } from '../../../providers'; import { CallControlsButton } from './CallControlsButton'; /** @@ -29,17 +28,16 @@ export const ToggleAudioPreviewButton = ({ variants: { buttonSizes }, }, } = useTheme(); + const call = useCall(); const { useMicrophoneState } = useCallStateHooks(); const { status } = useMicrophoneState(); - const { toggleInitialAudioMuteState } = useMediaStreamManagement(); - - const onPress = () => { + const onPress = async () => { if (onPressHandler) { onPressHandler(); return; } - toggleInitialAudioMuteState(); + await call?.microphone.toggle(); }; return ( diff --git a/packages/react-native-sdk/src/components/Call/CallControls/ToggleVideoPreviewButton.tsx b/packages/react-native-sdk/src/components/Call/CallControls/ToggleVideoPreviewButton.tsx index 673a06d7a4..9bc1495c1a 100644 --- a/packages/react-native-sdk/src/components/Call/CallControls/ToggleVideoPreviewButton.tsx +++ b/packages/react-native-sdk/src/components/Call/CallControls/ToggleVideoPreviewButton.tsx @@ -1,6 +1,5 @@ import React from 'react'; -import { useCallStateHooks } from '@stream-io/video-react-bindings'; -import { useMediaStreamManagement } from '../../../providers'; +import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings'; import { useTheme } from '../../../contexts'; import { CallControlsButton } from './CallControlsButton'; import { Video, VideoSlash } from '../../../icons'; @@ -29,15 +28,15 @@ export const ToggleVideoPreviewButton = ({ variants: { buttonSizes }, }, } = useTheme(); - const { toggleInitialVideoMuteState } = useMediaStreamManagement(); + const call = useCall(); const { useCameraState } = useCallStateHooks(); const { status } = useCameraState(); - const onPress = () => { + const onPress = async () => { if (onPressHandler) { onPressHandler(); return; } - toggleInitialVideoMuteState(); + await call?.camera.toggle(); }; return ( diff --git a/packages/react-native-sdk/src/index.ts b/packages/react-native-sdk/src/index.ts index 6322d53004..ce6fd43375 100644 --- a/packages/react-native-sdk/src/index.ts +++ b/packages/react-native-sdk/src/index.ts @@ -31,11 +31,6 @@ export * from './translations'; // Overriding 'StreamVideo' from '@stream-io/video-react-bindings' // Explicitly re-exporting to resolve ambiguity. -export { - StreamVideo, - StreamCall, - MediaStreamManagement, - useMediaStreamManagement, -} from './providers'; +export { StreamVideo, StreamCall, MediaStreamManagement } from './providers'; setClientDetails(); diff --git a/packages/react-native-sdk/src/providers/MediaStreamManagement.tsx b/packages/react-native-sdk/src/providers/MediaStreamManagement.tsx index 450a11bab1..7d76ab57cc 100644 --- a/packages/react-native-sdk/src/providers/MediaStreamManagement.tsx +++ b/packages/react-native-sdk/src/providers/MediaStreamManagement.tsx @@ -1,12 +1,4 @@ -import React, { - createContext, - PropsWithChildren, - useCallback, - useContext, - useEffect, - useMemo, - useState, -} from 'react'; +import React, { PropsWithChildren, useEffect, useState } from 'react'; import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings'; import { useAppStateListener } from '../utils/hooks'; @@ -21,29 +13,9 @@ export type MediaDevicesInitialState = { initialVideoEnabled?: boolean; }; -/** - * API to control device enablement, device selection and media stream access for a call. - * @category Device Management - */ -export type MediaStreamManagementContextAPI = { - /** - * Toggles the initialAudioEnabled boolean flag. - * The latest value set will be used to decide, whether audio stream will be published when joining a call. - */ - toggleInitialAudioMuteState: () => void; - /** - * Toggles the initialAudioEnabled boolean flag. - * The latest value set will be used to decide, whether audio stream will be published when joining a call. - */ - toggleInitialVideoMuteState: () => void; -}; - -const MediaStreamContext = - createContext(null); - /** * - * Provides `MediaStreamManagementContextAPI` that allow the integrators to handle: + * Provides `MediaStreamManagement` wrapper that allow the integrators to handle: * 1. the initial device state enablement (for example in a custom lobby component) * 2. media stream publishing * @param params @@ -71,121 +43,74 @@ export const MediaStreamManagement = ({ ); const [{ initialAudioEnabled, initialVideoEnabled }, setInitialDeviceState] = - useState({ - initialAudioEnabled: !!propInitialAudioEnabled, - initialVideoEnabled: !!propInitialVideoEnabled, + useState({ + initialAudioEnabled: undefined, + initialVideoEnabled: undefined, }); const settings = useCallSettings(); - // if prop is set, use that value.. the prop should override the backend settings + // Use backend settings to set initial audio/video enabled state + // It is applied only if the prop was undefined -- meaning user did not provide any value useEffect(() => { + if (!settings) { + return; + } + + const { audio, video } = settings; setInitialDeviceState((prev) => { let initAudio = prev.initialAudioEnabled; - if (typeof propInitialAudioEnabled !== 'undefined') { - initAudio = propInitialAudioEnabled; + if (typeof propInitialAudioEnabled === 'undefined') { + initAudio = audio.mic_default_on; } let initVideo = prev.initialVideoEnabled; - if (typeof propInitialVideoEnabled !== 'undefined') { - initVideo = propInitialVideoEnabled; + if (typeof propInitialVideoEnabled === 'undefined') { + initVideo = video.camera_default_on; } return { initialAudioEnabled: initAudio, initialVideoEnabled: initVideo }; }); - }, [propInitialAudioEnabled, propInitialVideoEnabled]); + }, [propInitialAudioEnabled, propInitialVideoEnabled, settings]); - // use backend settings to set initial audio/video enabled state - // ONLY if the prop was undefined -- meaning user did not provide any value + // Apply SDK settings to set the initial audio/video enabled state useEffect(() => { - if (!settings) { - return; - } - - const { audio, video } = settings; setInitialDeviceState((prev) => { let initAudio = prev.initialAudioEnabled; - if ( - typeof propInitialAudioEnabled === 'undefined' && - audio.mic_default_on - ) { - initAudio = true; + if (typeof propInitialAudioEnabled !== 'undefined') { + initAudio = propInitialAudioEnabled; } let initVideo = prev.initialVideoEnabled; - if ( - typeof propInitialVideoEnabled === 'undefined' && - video.camera_default_on - ) { - initVideo = true; + if (typeof propInitialVideoEnabled !== 'undefined') { + initVideo = propInitialVideoEnabled; } - return { initialAudioEnabled: initAudio, initialVideoEnabled: initVideo }; + + return { + initialAudioEnabled: initAudio, + initialVideoEnabled: initVideo, + }; }); - }, [propInitialAudioEnabled, propInitialVideoEnabled, settings]); + }, [propInitialAudioEnabled, propInitialVideoEnabled]); // The main logic // Enable or Disable the audio/video stream based on the initial state useEffect(() => { - if ( - initialAudioEnabled && - (call?.microphone.state.status === undefined || - call?.microphone.state.status === 'disabled') - ) { + if (initialAudioEnabled === undefined) { + return; + } + if (initialVideoEnabled === undefined) { + return; + } + if (initialAudioEnabled) { call?.microphone.enable(); - } else if ( - !initialAudioEnabled && - call?.microphone.state.status === 'enabled' - ) { + } else { call?.microphone.disable(); } - if ( - initialVideoEnabled && - (call?.camera.state.status === undefined || - call?.camera.state.status === 'disabled') - ) { + if (initialVideoEnabled) { call?.camera.enable(); - } else if ( - !initialVideoEnabled && - call?.camera.state.status === 'enabled' - ) { + } else { call?.camera.disable(); } }, [call, initialAudioEnabled, initialVideoEnabled]); - const toggleInitialAudioMuteState = useCallback(() => { - call?.microphone.state.status === 'enabled' - ? call?.microphone.disable() - : call?.microphone.enable(); - }, [call]); - - const toggleInitialVideoMuteState = useCallback(() => { - call?.camera.state.status === 'enabled' - ? call?.camera.disable() - : call?.camera.enable(); - }, [call]); - - const contextValue = useMemo(() => { - return { - toggleInitialAudioMuteState, - toggleInitialVideoMuteState, - }; - }, [toggleInitialAudioMuteState, toggleInitialVideoMuteState]); - - return ( - - {children} - - ); -}; - -/** - * Context consumer retrieving MediaStreamManagementContextAPI. - * @returns - * - * @category Device Management - */ -export const useMediaStreamManagement = () => { - const value = useContext(MediaStreamContext); - if (!value) { - console.warn('Null MediaDevicesContext'); - } - return value as MediaStreamManagementContextAPI; + return <>{children}; };