Preview
The preview screen is a frequently used UX element that allows users to check if their input devices are working properly and set the initial state (mute/unmute) of their audio and video tracks before joining.
100ms SDKs provide an easy-to-use API to back this feature. Additionally, the SDK will try to establish a connection to the 100ms server to verify there are no network issues and that the auth credentials are valid so that if everything is in order the subsequent room join will be much faster.
Let's look at the flow of HMSSDK
with a preview
Let's follow the steps of joining a room with a preview:
Initialize HMSSDK
late HMSSDK hmsSDK; HMSSDK hmsSDK = HMSSDK();
Call build method on HMSSDK instance
await hmsSDK.build(); // ensure to await while invoking the `build` method
Attach preview listeners and call preview method
Let's see the complete implementation till now:
class Preview implements HMSPreviewListener{ late HMSSDK hmsSDK; Preview(){ initHMSSDK(); } void initHMSSDK() async { hmsSDK = HMSSDK(); await hmsSDK.build(); // ensure to await while invoking the `build` method HMSConfig config = HMSConfig( userName: "John Doe", authToken: "eyJH5c", // client-side token generated from your token service ); //Here this is an instance of a class that implements HMSPreviewListener, that is, Preview hmsSDK.addPreviewListener(listener:this); hmsSDK.preview(config: config); } void onPreview( {required HMSRoom room, required List<HMSTrack> localTracks}) { /// We will get the callback here if the preview succeeds } void onHMSError({required HMSException error}) { //Error updates: https://www.100ms.live/docs/flutter/v2/features/error-handling#hms-exception } void onRoomUpdate( {required HMSRoom room, required HMSRoomUpdate update}) { /// Only sent when Preview Room State is enabled. /// Room updates: https://www.100ms.live/docs/flutter/v2/features/update-listener-enums#hms-room-update } void onPeerUpdate( {required HMSPeer peer, required HMSPeerUpdate update}) async { /// Only sent when Preview Room State is enabled. /// Peer updates: https://www.100ms.live/docs/flutter/v2/features/update-listener-enums#hms-peer-update } void onAudioDeviceChanged( {HMSAudioDevice? currentAudioDevice, List<HMSAudioDevice>? availableAudioDevice}) { /// Get notified when the audio device is changed: https://www.100ms.live/docs/flutter/v2/features/audio-output-routing#adding-audio-device-change-event-listener-android-only } void onPeerListUpdate( {required List<HMSPeer> addedPeers, required List<HMSPeer> removedPeers}){ ///When a room is joined we can get the list of peers in the room from `addedPeers` /// Get notified when a peer is added or removed: https://www.100ms.live/docs/flutter/v2/features/update-listener-enums#hms-peer-update } }
After calling preview your app will be provided an update from the 100ms SDK.
✅ If successful, the onPreview({required HMSRoom room, required List<HMSTrack> localTracks})
method of HMSPreviewListener will be invoked with information about the room encapsulated in the HMSRoom object.
❌ If failure, the onHMSError({required HMSException error})
method will be invoked with exact failure reason.
Render Preview
In case of success onPreview
provides an array of local tracks in the parameter localTracks
that you can display to the user (see Render Video and Mute sections for more details).
- Fetching the track in
onPreview
callback:
class Preview implements HMSPreviewListener{ ... List<HMSVideoTrack> videoTracks = []; void onPreview({required HMSRoom room, required List<HMSTrack> localTracks}) { for (var track in localTracks) { if (track.kind == HMSTrackKind.kHMSTrackKindVideo) { isVideoOn = !(track.isMute); videoTracks.add(track as HMSVideoTrack); } if (track.kind == HMSTrackKind.kHMSTrackKindAudio) { isAudioOn = !(track.isMute); } } } }
- Display the track using
HMSVideoView
:
//videoTracks is the List<HMSVideoTrack> which we have set above HMSVideoView( scaleType: ScaleType.SCALE_ASPECT_FILL, track:videoTracks[0],//setting the first track from videoTracks list to render on screen setMirror: true, matchParent: false, )
Check how we have implemented the preview in our sample app here
Remove HMSPreviewListener before calling join
class Preview implements HMSPreviewListener{ ... void removePreviewListener(){ //Here this is an instance of a class that implements HMSPreviewListener, that is, Preview hmsSDK.removePreviewListener(this); } }
After calling removePreviewListener
to remove HMSPreviewListener
call join
by passing the same HMSSDK instance and HMSConfig.
Call join method and attach HMSUpdateListener
class Meeting implements HMSUpdateListener{ late HMSSDK hmsSDK; Meeting({required HMSSDK hmsSDKFromPreview,HMSConfig configFromPreview}){ hmsSDK = hmsSDKFromPreview; hmsSDK.addUpdateListener(listener: this); hmsSDK.join(config: configFromPreview); } void onJoin({required HMSRoom room}) async { // User Joined successfully. } ... }
In this way, a room can be joined with Preview. The rest of the functions and their implementation is same as we do in the case of direct join.
Get onPeerUpdate and onRoomUpdate while in Preview Mode
To enable onPeerUpdate
& onRoomUpdate
in the Preview, we need to enable Room State from the 100ms Dashboard.
This can be enabled by selecting a Template and then navigating to Advanced Settings.
By default, Room State in Preview Mode is Disabled. So onPeerUpdate
& onRoomUpdate
events will not be received if these are not Enabled from Dashboard.
These options are available in advanced settings:
What if you leave the call after preview
In the event that a user exits the room after initiating the preview
but before proceeding to join
, it is recommended to invoke the leave
method to guarantee proper cleanup.
class Preview implements HMSUpdateListener{ late HMSSDK hmsSDK; ... ///Call leave method when a user leaves after preview ///The execution of the 'leave' method should also be triggered when the user presses the back button in the application. void leave(){ hmsSDK.leave(); } }
Supplementary bytes
Now, let's take a look at the listener class in detail.
///[HMSPreviewListener] listens to updates when you preview. /// ///Just implement it and get the preview updates. /// /// Check out the [Sample App] to know about how we are implementing it: https://github.com/100mslive/100ms-flutter. abstract class HMSPreviewListener { ///when an error is caught [onError] will be called /// /// - Parameters: /// - error: error which you get. void onHMSError({required HMSException error}); ///when you want to preview listen to this callback /// /// - Parameters: /// - room: the room which was joined /// - localTracks: local audio/video tracks list void onPreview({required HMSRoom room, required List<HMSTrack> localTracks}); /// This is called when there is a change in any property of the Room. /// Only sent when Preview Room State is enabled. /// /// - Parameters: /// - room: the room which was joined /// - update: the triggered update type. Should be used to perform different UI Actions void onRoomUpdate({required HMSRoom room, required HMSRoomUpdate update}); /// This will be called whenever there is an update on an existing peer /// or a new peer got added/existing peer is removed. /// Only sent when Preview Room State is enabled. /// /// This callback can be used to keep a track of all the peers in the room /// - Parameters: /// - peer: the peer who joined/left or was updated /// - update: the triggered update type. Should be used to perform different UI Actions void onPeerUpdate({required HMSPeer peer, required HMSPeerUpdate update}); ///whenever a new audio device is plugged in or the audio output is changed we ///get the onAudioDeviceChanged update ///This callback is only fired on Android devices. On iOS, this callback will not be triggered. /// - Parameters: /// - currentAudioDevice: Current audio output route /// - availableAudioDevice: List of available audio output devices void onAudioDeviceChanged( {HMSAudioDevice? currentAudioDevice, List<HMSAudioDevice>? availableAudioDevice}); ///Upon joining a room with existing peers, onPeerListUpdated will be called with the list of peers present ///in the room instead of getting onPeerUpdate for each peer in the room. ///Subsequent peer joins/leaves would be notified via both onPeerUpdate and onPeerListUpdated /// - Parameters: /// - addedPeers: List of peers who joined the room /// - removedPeers: List of peers who left the room void onPeerListUpdate( {required List<HMSPeer> addedPeers, required List<HMSPeer> removedPeers}); }