communication-react-19
Version:
React library for building modern communication user experiences utilizing Azure Communication Services (React 19 compatible fork)
101 lines • 5.3 kB
JavaScript
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { useEffect, useMemo, useState } from 'react';
import { callingComponentLogger } from '../utils/Logger';
/**
* Helper hook to maintain the video stream lifecycle. This calls onCreateStreamView and onDisposeStreamView
* appropriately based on react lifecycle events and prop changes.
*
* @remarks
*
* Notes on handling changes to scaling mode:
*
* Ideally we have access to the original StreamRenderView and can call view.updateScalingMode() and do not need to recreate the stream view.
* However, to support backwards compat we cannot guarantee this. If we don't have access to the original StreamRenderView we need to dispose
* the old view and create a new one.
*
* Supporting both of these scenarios became too complex and fragile. When we introduce a breaking change this should be update to ensure that
* onCreateStreamView _must_ return a view object with updateScalingMode and update logic in this hook to call view.updateScalingMode instead
* of recreating the stream.
*
* @private
*/
const useVideoStreamLifecycleMaintainer = (props) => {
const { isMirrored, isScreenSharingOn, isStreamAvailable, onCreateStreamView, onDisposeStreamView, renderElementExists, scalingMode, streamId, isVideoPermitted } = props;
const [videoStreamViewResult, setVideoStreamViewResult] = useState();
useEffect(() => {
var _a;
if (isVideoPermitted !== false && isStreamAvailable && !renderElementExists) {
(_a = onCreateStreamView === null || onCreateStreamView === void 0 ? void 0 : onCreateStreamView({ isMirrored, scalingMode })) === null || _a === void 0 ? void 0 : _a.then((result) => {
result && setVideoStreamViewResult(result);
});
}
// Always clean up element to make tile up to date and be able to dispose correctly
return () => {
if (renderElementExists) {
// TODO: Remove `if isScreenSharingOn` when we isolate dispose behavior for screen share
if (!isScreenSharingOn) {
onDisposeStreamView === null || onDisposeStreamView === void 0 ? void 0 : onDisposeStreamView();
}
}
else {
callingComponentLogger.warning('Stream view element does not exist when disposing stream view');
}
};
}, [
isMirrored,
isScreenSharingOn,
isStreamAvailable,
onCreateStreamView,
onDisposeStreamView,
renderElementExists,
scalingMode,
streamId,
isVideoPermitted
]);
// The execution order for above useEffect is onCreateRemoteStreamView =>(async time gap) RenderElement generated => element disposed => onDisposeRemoteStreamView
// Element disposed could happen during async time gap, which still cause leaks for unused renderElement.
// Need to do an entire cleanup when remoteTile gets disposed and make sure element gets correctly disposed
useEffect(() => {
return () => {
// TODO: Remove `if isScreenSharingOn` when we isolate dispose behavior for screen share
if (!isScreenSharingOn) {
onDisposeStreamView === null || onDisposeStreamView === void 0 ? void 0 : onDisposeStreamView();
}
};
}, [isScreenSharingOn, onDisposeStreamView]);
return videoStreamViewResult;
};
/**
* Extension of {@link useVideoStreamLifecycleMaintainer} specifically for local video streams
*
* @private
*/
export const useLocalVideoStreamLifecycleMaintainer = (props) => {
const { onCreateLocalStreamView, onDisposeLocalStreamView } = props;
const onCreateStreamView = useMemo(() => (options) => {
return onCreateLocalStreamView === null || onCreateLocalStreamView === void 0 ? void 0 : onCreateLocalStreamView(options);
}, [onCreateLocalStreamView]);
const onDisposeStreamView = useMemo(() => () => {
onDisposeLocalStreamView === null || onDisposeLocalStreamView === void 0 ? void 0 : onDisposeLocalStreamView();
}, [onDisposeLocalStreamView]);
return useVideoStreamLifecycleMaintainer(Object.assign(Object.assign({}, props), { onCreateStreamView,
onDisposeStreamView }));
};
/**
* Extension of {@link useVideoStreamLifecycleMaintainer} specifically for remote video streams
*
* @private
*/
export const useRemoteVideoStreamLifecycleMaintainer = (props) => {
const { remoteParticipantId, onCreateRemoteStreamView, onDisposeRemoteStreamView } = props;
const onCreateStreamView = useMemo(() => (options) => {
return onCreateRemoteStreamView === null || onCreateRemoteStreamView === void 0 ? void 0 : onCreateRemoteStreamView(remoteParticipantId, options);
}, [onCreateRemoteStreamView, remoteParticipantId]);
const onDisposeStreamView = useMemo(() => () => {
onDisposeRemoteStreamView === null || onDisposeRemoteStreamView === void 0 ? void 0 : onDisposeRemoteStreamView(remoteParticipantId);
}, [onDisposeRemoteStreamView, remoteParticipantId]);
return useVideoStreamLifecycleMaintainer(Object.assign(Object.assign({}, props), { onCreateStreamView,
onDisposeStreamView }));
};
//# sourceMappingURL=useVideoStreamLifecycleMaintainer.js.map