Overview
It all comes down to this. All the setup so far has been done so that we can show live streaming video in our beautiful apps.
-
First, you need to get all the peers in the room. You can use the
selectPeers
selector for this. -
Next, you'll need to have a reference to a video element. You must add the attributes as present below.
<video autoplay muted playsinline />
- You can then iterate over all the peers, and call the
attachVideo
function in hmsActions to render the video.
hmsActions.attachVideo(videoTrack.id, videoElement);
The videos will now be rendered & start playing on your screen. 🥳
In case you want to render local peer and remote peers separately, you can use the selectors - selectLocalPeer
and selectRemotePeers
.
Detach video to conserve bandwidth and cleanup elements
You can call detachVideo
on the hmsActions
to unsubscribe a track and not fetch it's data. This can be done
for example when a video goes out of view. This should also be called when the component is going to be unmounted
for proper cleanups of the video elements.
hmsActions.detachVideo(videoTrack.id, videoElement);
When to attach/detach videos
Starting from this release, sdk handles the subsequent attach/detach automatically.
- attach needs to be called only the first time the video element is available. subsequent calls will be ignored.
- detach needs to be called only when the element is removed from the dom while the track is still available. For the majority of cases, calling detach won't be needed.
To disable the auto handling by sdk, pass autoManageVideo: false
in join or preview config object. Then you will have to follow the below snippet
to handle video rendering on your end.
We need to re-attach video when it's in view after every:
- Unmute(when track.enable is true)
- Plugin is added/removed(for example, enable/disable virtual background)
- Camera/device change(track.deviceId is changed)
You can achieve all this by using the selectVideoTrackByID
selector and the aforementioned hmsActions.attachVideo
and hmsActions.detachVideo
functions.
// assuming you have peer object and video element // complete code snippet below hmsStore.subscribe((track) => { if (!track) { return; } if (track?.enabled) { hmsActions.attachVideo(track.id, videoElement); } else { hmsActions.detachVideo(track.id, videoElement); } }, selectVideoTrackByID(peer.videoTrack));
Note that if you're using the useVideo
hook from react-sdk
this is already being taken care of.
Example Snippet
import { hmsActions } from './hms'; const peersContainer = document.getElementById('peers-container'); // store peer IDs already rendered to avoid re-render on mute/unmute const renderedPeerIDs = new Set(); // render a single peer video tile function renderPeer(peer) { const peerTileDiv = document.createElement('div'); // you can either get an existing video element or create a new one. const videoElement = document.createElement('video'); const peerTileName = document.createElement('div'); videoElement.autoplay = true; videoElement.muted = true; videoElement.playsinline = true; peerTileName.textContent = peer.name; hmsStore.subscribe((track) => { if (!track) { return; } if (track.enabled) { hmsActions.attachVideo(track.id, videoElement); } else { hmsActions.detachVideo(track.id, videoElement); } }, selectVideoTrackByID(peer.videoTrack)); peerTileDiv.append(videoElement); peerTileDiv.append(peerTileName); renderedPeerIDs.add(peer.id); return peerTileDiv; } // display a tile for each peer in the peer list function renderPeers(peers) { peersContainer = document.getElementById('peers-container'); peers.forEach((peer) => { if (!renderedPeerIDs.has(peer.id) && peer.videoTrack) { console.log( `rendering video for peer - ${peer.name}, roleName - ${peer.roleName}, isLocal- ${peer.isLocal}` ); peersContainer.append(renderVideo(peer)); } }); } // subscribe to the peers, so render is called whenever there is a change like peer join and leave hmsStore.subscribe(renderPeers, selectPeers);
Mirror video
To mirror local peer's video, apply the following CSS style to the video
element.
/** enable mirror with -1 */ transform: scaleX(-1);
The 100ms sample app already does this by default. To turn it off, you can override this styling in code or disable the "Mirror Local Tile" from layout settings.