fix(webcam): turn useGetStats hook into a service method to avoid function re-instantiation
This commit is contained in:
parent
62662ee415
commit
8b4a2f39e0
@ -3,7 +3,6 @@ import { useMutation } from '@apollo/client';
|
|||||||
import { UPDATE_CONNECTION_ALIVE_AT } from './mutations';
|
import { UPDATE_CONNECTION_ALIVE_AT } from './mutations';
|
||||||
import { getStatus, handleAudioStatsEvent, startMonitoringNetwork } from '/imports/ui/components/connection-status/service';
|
import { getStatus, handleAudioStatsEvent, startMonitoringNetwork } from '/imports/ui/components/connection-status/service';
|
||||||
import connectionStatus from '../../core/graphql/singletons/connectionStatus';
|
import connectionStatus from '../../core/graphql/singletons/connectionStatus';
|
||||||
import { useGetStats } from '../video-provider/hooks';
|
|
||||||
|
|
||||||
import getBaseUrl from '/imports/ui/core/utils/getBaseUrl';
|
import getBaseUrl from '/imports/ui/core/utils/getBaseUrl';
|
||||||
|
|
||||||
@ -14,8 +13,6 @@ const ConnectionStatus = () => {
|
|||||||
|
|
||||||
const [updateConnectionAliveAtM] = useMutation(UPDATE_CONNECTION_ALIVE_AT);
|
const [updateConnectionAliveAtM] = useMutation(UPDATE_CONNECTION_ALIVE_AT);
|
||||||
|
|
||||||
const getVideoStreamsStats = useGetStats();
|
|
||||||
|
|
||||||
const handleUpdateConnectionAliveAt = () => {
|
const handleUpdateConnectionAliveAt = () => {
|
||||||
const startTime = performance.now();
|
const startTime = performance.now();
|
||||||
fetch(
|
fetch(
|
||||||
@ -66,7 +63,7 @@ const ConnectionStatus = () => {
|
|||||||
|
|
||||||
if (STATS_ENABLED) {
|
if (STATS_ENABLED) {
|
||||||
window.addEventListener('audiostats', handleAudioStatsEvent);
|
window.addEventListener('audiostats', handleAudioStatsEvent);
|
||||||
startMonitoringNetwork(getVideoStreamsStats);
|
startMonitoringNetwork();
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
@ -3,7 +3,6 @@ import { CONNECTION_STATUS_REPORT_SUBSCRIPTION } from '../queries';
|
|||||||
import Service from '../service';
|
import Service from '../service';
|
||||||
import Component from './component';
|
import Component from './component';
|
||||||
import useCurrentUser from '/imports/ui/core/hooks/useCurrentUser';
|
import useCurrentUser from '/imports/ui/core/hooks/useCurrentUser';
|
||||||
import { useGetStats } from '../../video-provider/hooks';
|
|
||||||
import useDeduplicatedSubscription from '/imports/ui/core/hooks/useDeduplicatedSubscription';
|
import useDeduplicatedSubscription from '/imports/ui/core/hooks/useDeduplicatedSubscription';
|
||||||
import { useReactiveVar } from '@apollo/client';
|
import { useReactiveVar } from '@apollo/client';
|
||||||
import connectionStatus from '/imports/ui/core/graphql/singletons/connectionStatus';
|
import connectionStatus from '/imports/ui/core/graphql/singletons/connectionStatus';
|
||||||
@ -16,14 +15,11 @@ const ConnectionStatusContainer = (props) => {
|
|||||||
|
|
||||||
const newtworkData = useReactiveVar(connectionStatus.getNetworkDataVar());
|
const newtworkData = useReactiveVar(connectionStatus.getNetworkDataVar());
|
||||||
|
|
||||||
const getVideoStreamsStats = useGetStats();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Component
|
<Component
|
||||||
{...props}
|
{...props}
|
||||||
connectionData={connectionData}
|
connectionData={connectionData}
|
||||||
amIModerator={amIModerator}
|
amIModerator={amIModerator}
|
||||||
getVideoStreamsStats={getVideoStreamsStats}
|
|
||||||
networkData={newtworkData}
|
networkData={newtworkData}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -5,6 +5,7 @@ import Session from '/imports/ui/services/storage/in-memory';
|
|||||||
import { notify } from '/imports/ui/services/notification';
|
import { notify } from '/imports/ui/services/notification';
|
||||||
import AudioService from '/imports/ui/components/audio/service';
|
import AudioService from '/imports/ui/components/audio/service';
|
||||||
import ScreenshareService from '/imports/ui/components/screenshare/service';
|
import ScreenshareService from '/imports/ui/components/screenshare/service';
|
||||||
|
import VideoService from '/imports/ui/components/video-provider/service';
|
||||||
import connectionStatus from '../../core/graphql/singletons/connectionStatus';
|
import connectionStatus from '../../core/graphql/singletons/connectionStatus';
|
||||||
|
|
||||||
const intlMessages = defineMessages({
|
const intlMessages = defineMessages({
|
||||||
@ -210,8 +211,8 @@ const getAudioData = async () => {
|
|||||||
* @returns An Object containing video data for all video peers and screenshare
|
* @returns An Object containing video data for all video peers and screenshare
|
||||||
* peer
|
* peer
|
||||||
*/
|
*/
|
||||||
const getVideoData = async (getVideoStreamsStats) => {
|
const getVideoData = async () => {
|
||||||
const camerasData = await getVideoStreamsStats() || {};
|
const camerasData = await VideoService.getStats() || {};
|
||||||
|
|
||||||
const screenshareData = await ScreenshareService.getStats() || {};
|
const screenshareData = await ScreenshareService.getStats() || {};
|
||||||
|
|
||||||
@ -226,10 +227,10 @@ const getVideoData = async (getVideoStreamsStats) => {
|
|||||||
* For audio, this will get information about the mic/listen-only stream.
|
* For audio, this will get information about the mic/listen-only stream.
|
||||||
* @returns An Object containing all this data.
|
* @returns An Object containing all this data.
|
||||||
*/
|
*/
|
||||||
const getNetworkData = async (getVideoStreamsStats) => {
|
const getNetworkData = async () => {
|
||||||
const audio = await getAudioData();
|
const audio = await getAudioData();
|
||||||
|
|
||||||
const video = await getVideoData(getVideoStreamsStats);
|
const video = await getVideoData();
|
||||||
|
|
||||||
const user = {
|
const user = {
|
||||||
time: new Date(),
|
time: new Date(),
|
||||||
@ -401,11 +402,11 @@ export function getStatus(levels, value) {
|
|||||||
* Start monitoring the network data.
|
* Start monitoring the network data.
|
||||||
* @return {Promise} A Promise that resolves when process started.
|
* @return {Promise} A Promise that resolves when process started.
|
||||||
*/
|
*/
|
||||||
export async function startMonitoringNetwork(getVideoStreamsStats) {
|
export async function startMonitoringNetwork() {
|
||||||
let previousData = await getNetworkData(getVideoStreamsStats);
|
let previousData = await getNetworkData();
|
||||||
|
|
||||||
setInterval(async () => {
|
setInterval(async () => {
|
||||||
const data = await getNetworkData(getVideoStreamsStats);
|
const data = await getNetworkData();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
outbound: audioCurrentUploadRate,
|
outbound: audioCurrentUploadRate,
|
||||||
|
@ -20,7 +20,6 @@ import VideoService from './service';
|
|||||||
import { Output } from '/imports/ui/components/layout/layoutTypes';
|
import { Output } from '/imports/ui/components/layout/layoutTypes';
|
||||||
import { VideoItem } from './types';
|
import { VideoItem } from './types';
|
||||||
import { debounce } from '/imports/utils/debounce';
|
import { debounce } from '/imports/utils/debounce';
|
||||||
import WebRtcPeer from '/imports/ui/services/webrtc-base/peer';
|
|
||||||
import useSettings from '/imports/ui/services/settings/hooks/useSettings';
|
import useSettings from '/imports/ui/services/settings/hooks/useSettings';
|
||||||
import { SETTINGS } from '/imports/ui/services/settings/enums';
|
import { SETTINGS } from '/imports/ui/services/settings/enums';
|
||||||
import { useStorageKey } from '/imports/ui/services/storage/hooks';
|
import { useStorageKey } from '/imports/ui/services/storage/hooks';
|
||||||
@ -64,7 +63,7 @@ const VideoProviderContainer: React.FC<VideoProviderContainerProps> = (props) =>
|
|||||||
VideoService.applyCameraProfile,
|
VideoService.applyCameraProfile,
|
||||||
CAMERA_QUALITY_THR_DEBOUNCE,
|
CAMERA_QUALITY_THR_DEBOUNCE,
|
||||||
{ leading: false, trailing: true },
|
{ leading: false, trailing: true },
|
||||||
);
|
) as typeof VideoService.applyCameraProfile;
|
||||||
|
|
||||||
const { data: currentMeeting } = useMeeting((m) => ({
|
const { data: currentMeeting } = useMeeting((m) => ({
|
||||||
usersPolicies: m.usersPolicies,
|
usersPolicies: m.usersPolicies,
|
||||||
@ -89,6 +88,7 @@ const VideoProviderContainer: React.FC<VideoProviderContainerProps> = (props) =>
|
|||||||
totalNumberOfStreams,
|
totalNumberOfStreams,
|
||||||
totalNumberOfOtherStreams,
|
totalNumberOfOtherStreams,
|
||||||
} = useVideoStreams();
|
} = useVideoStreams();
|
||||||
|
VideoService.updateActivePeers(streams);
|
||||||
|
|
||||||
let usersVideo: VideoItem[] = streams;
|
let usersVideo: VideoItem[] = streams;
|
||||||
|
|
||||||
@ -167,7 +167,7 @@ const VideoProviderContainer: React.FC<VideoProviderContainerProps> = (props) =>
|
|||||||
exitVideo={exitVideo}
|
exitVideo={exitVideo}
|
||||||
lockUser={lockUser}
|
lockUser={lockUser}
|
||||||
stopVideo={stopVideo}
|
stopVideo={stopVideo}
|
||||||
applyCameraProfile={applyCameraProfile as (peer: WebRtcPeer, profileId: string) => void}
|
applyCameraProfile={applyCameraProfile}
|
||||||
myRole={myRole}
|
myRole={myRole}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -52,11 +52,6 @@ import ConnectionStatus from '/imports/ui/core/graphql/singletons/connectionStat
|
|||||||
import { VIDEO_TYPES } from '/imports/ui/components/video-provider/enums';
|
import { VIDEO_TYPES } from '/imports/ui/components/video-provider/enums';
|
||||||
import createUseSubscription from '/imports/ui/core/hooks/createUseSubscription';
|
import createUseSubscription from '/imports/ui/core/hooks/createUseSubscription';
|
||||||
|
|
||||||
const FILTER_VIDEO_STATS = [
|
|
||||||
'outbound-rtp',
|
|
||||||
'inbound-rtp',
|
|
||||||
];
|
|
||||||
|
|
||||||
const useVideoStreamsSubscription = createUseSubscription(
|
const useVideoStreamsSubscription = createUseSubscription(
|
||||||
VIDEO_STREAMS_SUBSCRIPTION,
|
VIDEO_STREAMS_SUBSCRIPTION,
|
||||||
{},
|
{},
|
||||||
@ -532,53 +527,6 @@ export const useStopVideo = () => {
|
|||||||
}, [cameraBroadcastStop]);
|
}, [cameraBroadcastStop]);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useActivePeers = () => {
|
|
||||||
const videoData = useVideoStreams();
|
|
||||||
|
|
||||||
if (!videoData) return null;
|
|
||||||
|
|
||||||
const { streams: activeVideoStreams } = videoData;
|
|
||||||
|
|
||||||
if (!activeVideoStreams) return null;
|
|
||||||
|
|
||||||
const activePeers: Record<string, RTCPeerConnection> = {};
|
|
||||||
|
|
||||||
activeVideoStreams.forEach((stream) => {
|
|
||||||
if (videoService.getWebRtcPeersRef()[stream.stream]) {
|
|
||||||
activePeers[stream.stream] = videoService.getWebRtcPeersRef()[stream.stream].peerConnection;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return activePeers;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useGetStats = () => {
|
|
||||||
const peers = useActivePeers();
|
|
||||||
|
|
||||||
return useCallback(async () => {
|
|
||||||
if (!peers) return null;
|
|
||||||
|
|
||||||
const stats: Record<string, unknown> = {};
|
|
||||||
|
|
||||||
await Promise.all(
|
|
||||||
Object.keys(peers).map(async (peerId) => {
|
|
||||||
const peerStats = await peers[peerId].getStats();
|
|
||||||
|
|
||||||
const videoStats: Record<string, unknown> = {};
|
|
||||||
|
|
||||||
peerStats.forEach((stat) => {
|
|
||||||
if (FILTER_VIDEO_STATS.includes(stat.type)) {
|
|
||||||
videoStats[stat.type] = stat;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
stats[peerId] = videoStats;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
return stats;
|
|
||||||
}, [peers]);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useShouldRenderPaginationToggle = () => {
|
export const useShouldRenderPaginationToggle = () => {
|
||||||
const myPageSize = useMyPageSize();
|
const myPageSize = useMyPageSize();
|
||||||
const {
|
const {
|
||||||
|
@ -18,11 +18,16 @@ import WebRtcPeer from '/imports/ui/services/webrtc-base/peer';
|
|||||||
import { Constraints2 } from '/imports/ui/Types/meetingClientSettings';
|
import { Constraints2 } from '/imports/ui/Types/meetingClientSettings';
|
||||||
import MediaStreamUtils from '/imports/utils/media-stream-utils';
|
import MediaStreamUtils from '/imports/utils/media-stream-utils';
|
||||||
import Session from '/imports/ui/services/storage/in-memory';
|
import Session from '/imports/ui/services/storage/in-memory';
|
||||||
import type { Stream } from './types';
|
import type { Stream, StreamItem } from './types';
|
||||||
import { VIDEO_TYPES } from './enums';
|
import { VIDEO_TYPES } from './enums';
|
||||||
|
|
||||||
const TOKEN = '_';
|
const TOKEN = '_';
|
||||||
|
|
||||||
|
const FILTER_VIDEO_STATS = [
|
||||||
|
'outbound-rtp',
|
||||||
|
'inbound-rtp',
|
||||||
|
];
|
||||||
|
|
||||||
class VideoService {
|
class VideoService {
|
||||||
public isMobile: boolean;
|
public isMobile: boolean;
|
||||||
|
|
||||||
@ -40,6 +45,8 @@ class VideoService {
|
|||||||
|
|
||||||
private deviceId: string | null = null;
|
private deviceId: string | null = null;
|
||||||
|
|
||||||
|
private activePeers: Record<string, RTCPeerConnection>;
|
||||||
|
|
||||||
private readonly clientSessionUUID: string;
|
private readonly clientSessionUUID: string;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -60,6 +67,7 @@ class VideoService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.webRtcPeersRef = {};
|
this.webRtcPeersRef = {};
|
||||||
|
this.activePeers = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
static fetchNumberOfDevices(devices: MediaDeviceInfo[]) {
|
static fetchNumberOfDevices(devices: MediaDeviceInfo[]) {
|
||||||
@ -474,6 +482,39 @@ class VideoService {
|
|||||||
getPrefix() {
|
getPrefix() {
|
||||||
return `${Auth.userID}${TOKEN}${this.clientSessionUUID}`;
|
return `${Auth.userID}${TOKEN}${this.clientSessionUUID}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateActivePeers(streams: StreamItem[]) {
|
||||||
|
const activePeers: Record<string, RTCPeerConnection> = {};
|
||||||
|
|
||||||
|
streams.forEach((vs) => {
|
||||||
|
if (this.webRtcPeersRef[vs.stream]) {
|
||||||
|
activePeers[vs.stream] = this.webRtcPeersRef[vs.stream].peerConnection;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.activePeers = activePeers;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getStats() {
|
||||||
|
const stats: Record<string, unknown> = {};
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
Object.keys(this.activePeers).map(async (peerId) => {
|
||||||
|
const peerStats = await this.activePeers[peerId].getStats();
|
||||||
|
|
||||||
|
const videoStats: Record<string, unknown> = {};
|
||||||
|
|
||||||
|
peerStats.forEach((stat) => {
|
||||||
|
if (FILTER_VIDEO_STATS.includes(stat.type)) {
|
||||||
|
videoStats[stat.type] = stat;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
stats[peerId] = videoStats;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const videoService = new VideoService();
|
const videoService = new VideoService();
|
||||||
@ -516,4 +557,6 @@ export default {
|
|||||||
getRoleViewer: VideoService.getRoleViewer,
|
getRoleViewer: VideoService.getRoleViewer,
|
||||||
getPrefix: videoService.getPrefix.bind(videoService),
|
getPrefix: videoService.getPrefix.bind(videoService),
|
||||||
isPinEnabled: VideoService.isPinEnabled,
|
isPinEnabled: VideoService.isPinEnabled,
|
||||||
|
updateActivePeers: (streams: StreamItem[]) => videoService.updateActivePeers(streams),
|
||||||
|
getStats: () => videoService.getStats(),
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user