react-native-whip-whep
Version:
An implementation of WHIP and WHEP protocols functionalities for React Native.
96 lines • 4.26 kB
JavaScript
import { requireNativeViewManager } from "expo-modules-core";
import * as React from "react";
import { PlayerType, } from "./ReactNativeMobileWhepClient.types";
const NativeViewBase = requireNativeViewManager("ReactNativeMobileWhipClientViewModule");
const NativeView = NativeViewBase;
/**
* A component that renders a native view for WHIP player type.
*
* This component accepts style and other props defined in
* ReactNativeMobileWhipClientViewProps.
*
* @param {ReactNativeMobileWhipClientViewProps & { ref?: React.Ref<WhipClientViewRef> }} props - The properties to customize the component.
* @returns {JSX.Element} The rendered component.
*/
export function WhipClientView(props) {
const { ref, ...rest } = props;
const nativeRef = React.useRef(null);
/**
* WORKAROUND: Race condition with Expo's ConcurrentFunctionDefinition
*
* The native view is created on a different queue than the function initialization,
* which can cause `initializeCamera` to be called before the view is fully created.
*
* This results in the following error:
* ```
* Error: Calling the 'initializeCamera' function has failed
* Caused by: The 1st argument cannot be cast to type View<ReactNativeMobileWhipClientView>
* Caused by: Unable to find the 'ReactNativeMobileWhipClientView' view with tag '122'
* code: 'ERR_ARGUMENT_CAST'
* ```
*
* The `setTimeout(0)` defers execution to the next event loop tick, which seems like enough for the view to be created.
*
* This is the how they are trying to solving as of writing this comment: https://github.com/expo/expo/blob/3f3ad4f6f9ea096bb003c4345f0a09f2a41b3f25/packages/expo-modules-core/ios/Core/Functions/AsyncFunctionDefinition.swift#L125
* This might get fixed in the future and setTimeout won't be needed anymore.
*/
React.useImperativeHandle(ref, () => ({
initializeCamera: async (options, videoDeviceId) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
nativeRef.current
?.initializeCamera(options, videoDeviceId)
.then(() => {
resolve();
})
.catch((error) => {
reject(error);
});
}, 0);
});
},
initializeScreenShare: async (options) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
nativeRef.current
?.initializeScreenShare(options)
.then(() => {
resolve();
})
.catch((error) => {
reject(error);
});
}, 0);
});
},
connect: async (options) => {
await nativeRef.current?.connect(options);
},
disconnect: async () => {
await nativeRef.current?.disconnect();
},
switchCamera: async (deviceId) => {
await nativeRef.current?.switchCamera(deviceId);
},
flipCamera: async () => {
await nativeRef.current?.flipCamera();
},
setPreferredSenderVideoCodecs: async (preferredCodecs) => {
await nativeRef.current?.setPreferredSenderVideoCodecs(preferredCodecs);
},
setPreferredSenderAudioCodecs: async (preferredCodecs) => {
await nativeRef.current?.setPreferredSenderAudioCodecs(preferredCodecs);
},
getSupportedSenderVideoCodecsNames: async () => {
return ((await nativeRef.current?.getSupportedSenderVideoCodecsNames()) ?? []);
},
getSupportedSenderAudioCodecsNames: async () => {
return ((await nativeRef.current?.getSupportedSenderAudioCodecsNames()) ?? []);
},
currentCameraDeviceId: async () => {
return (await nativeRef.current?.currentCameraDeviceId()) ?? "";
},
}));
return <NativeView {...rest} playerType={PlayerType.WHIP} ref={nativeRef}/>;
}
//# sourceMappingURL=ReactNativeMobileWhipClientView.js.map