// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import React, { useCallback, useEffect, useState, } from 'react'; import { VideoTileState } from 'amazon-chime-sdk-js'; import { useAudioVideo } from '../providers/AudioVideoProvider'; import { useRoster } from '../providers/RosterProvider'; import VideoGrid from '../components/VideoGrid'; import RemoteVideo from '../components/RemoteVideo'; import { MAX_REMOTE_VIDEOS } from '../constants'; const RemoteVideoGrid: React.FC = () => { const roster = useRoster(); const tiles: { [index: number]: number } = {}; const videoElements: HTMLVideoElement[] = []; // an array of 16 HTMLVideoElement objects const [visibleIndices, setVisibleIndices] = useState<{ [index: string]: { boundAttendeeId: string }; }>({}); const audioVideo = useAudioVideo(); const acquireTileIndex = (tileId: number): number => { for (let index = 0; index < MAX_REMOTE_VIDEOS; index++) { if (tiles[index] === tileId) { return index; } } for (let index = 0; index < MAX_REMOTE_VIDEOS; index++) { if (!(index in tiles)) { tiles[index] = tileId; return index; } } throw new Error('no tiles are available'); }; const releaseTileIndex = (tileId: number): number => { for (let index = 0; index < MAX_REMOTE_VIDEOS; index++) { if (tiles[index] === tileId) { delete tiles[index]; return index; } } return MAX_REMOTE_VIDEOS; }; useEffect(() => { if (!audioVideo) { return; } const videoTileDidUpdate = (tileState: VideoTileState) => { const { boundAttendeeId, localTile, isContent, tileId } = tileState; if (!boundAttendeeId || localTile || isContent || !tileId) { return; } const index = acquireTileIndex(tileId); audioVideo.bindVideoElement(tileId, videoElements[index]); setVisibleIndices((previousVisibleIndices) => ({ ...previousVisibleIndices, [index]: { boundAttendeeId: boundAttendeeId }, })); }; const videoTileWasRemoved = (tileId: number) => { const index = releaseTileIndex(tileId); setVisibleIndices((previousVisibleIndices) => ({ ...previousVisibleIndices, [index]: null, })); }; const observers = { videoTileDidUpdate, videoTileWasRemoved }; audioVideo.addObserver(observers); return () => { audioVideo.removeObserver(observers); }; }, [audioVideo]); const numberOfVisibleIndices = Object.keys(visibleIndices).reduce( (result: number, key: string) => result + (visibleIndices[key] ? 1 : 0), 0 ); return (
{Array.from(Array(MAX_REMOTE_VIDEOS).keys()).map((key, index) => { const visibleIndex = visibleIndices && visibleIndices[index]; let rosterAttendee; if (visibleIndex && roster) { rosterAttendee = roster[visibleIndex.boundAttendeeId]; } return ( { if (element) { videoElements[index] = element; } }, [])} /> ) })}
); } export default RemoteVideoGrid;