Remote Mute

You're running a video call room and decide that someone who's currently talking shouldn't be talking.

You'd prefer they'd stay mute. Or perhaps you want their video turned off as well as their audio. You're looking for a remote mute.

Muting can apply to both audio and video.

Unmuting

You may also decide that you want to let someone else speak who was currently muted. Or may want to ask someone to turn on their video.

You can request people to unmute themselves as well.

Permissions

Can't let just anyone mute others. First you need to create a role with the permissions to mute others and also to ask them to unmute.

The permission to mute others is within PermissionsParams mute and you should check for that within the HMSRole of the peer to see if they have it.

Similarly the permission to unmute other peers is within PermissionsParams unmute.

Here's how to check whether the local peer has the permission to mute or unmute others:

fun isAllowedToMuteOthers(): Boolean { return hmsSDK.getLocalPeer()!! .hmsRole.permission? .mute == true } fun isAllowedToUnMuteOthers(): Boolean { return hmsSDK.getLocalPeer()!! .hmsRole.permission? .unmute == true }

hmsSdk.getLocalPeer() will not return null as long as you're in a preview or in a meeting. Since you likely won't need to check for permissions if you're not in one it would be ok.

Muting/Unmuting

There are two APIs for muting/unmuting. changeTrackState is the overloaded function which handles both.

  • One which only works on a single track (audio/video) for a single peer at a time. changeTrackState(forRemoteTrack: HMSTrack, mute: Boolean, hmsActionResultListener: HMSActionResultListener)
  • One which can mute multiple tracks for multiple peers. Either by their role, or track source or track type or any combination of the above. changeTrackState(mute: Boolean, type : HMSTrackType?, source : String?, roles : List<HMSRole>?, hmsActionResultListener: HMSActionResultListener)

For single peer/track scroll to "Single Peer or Track".

For multiple peer/track muting simultaneously scroll to Multiple Peers or Tracks.

Single Peer or Track

Once you have checked that the caller has permissions to mute another peer's audio or video, call for it with hmsSdk.changeTrackState.

To mute audio for a single peer or track:

hmsSdk.changeTrackState takes three parameters:

hmsTrack: The HMSTrack that should be muted or unmuted. Can be audio or video.

mute: A Boolean where true indicates that it should be muted. false indicates that it should be unmuted.

hmsActionResultListener: A HMSActionResultListener instance which will receive onSuccess if the server acknowledges the the request as valid. onError if there was an exception along with the HMSException for it.

fun changeAudioState(hmsRemotePeer: HMSRemotePeer, mute : Boolean) { val track = hmsRemotePeer.audioTrack if(track != null) { hmsSdk.changeTrackState(track, mute, object : HMSActionResultListener { override fun onError(error: HMSException) { } override fun onSuccess() { } }) } }

Similarly the video track can be muted or unmuted.

fun changeVideoState(hmsRemotePeer: HMSRemotePeer, mute : Boolean) { val track = hmsRemotePeer.videoTrack if(track != null) { hmsSdk.changeTrackState(track, mute, object : HMSActionResultListener { override fun onError(error: HMSException) { } override fun onSuccess() { } }) } }

Handling a mute callback

Mute callbacks are automatically applied to the receiver. No action is required.

However there will still be a callback to onChangeTrackStateRequest after the SDK mutes the user.

If you're doing something when the user receives a request, such as showing them a dialog, a check of the type would help avoid showing it unnecessarily:

override fun onChangeTrackStateRequest(details: HMSChangeTrackStateRequest) { if (details.track.isMute != details.mute) { // Handle HMSChangeTrackStateRequest } }

Without which, on a mute request the track will be muted and you'll still get a request on the caller side to mute.

Handling an unmute callback

Unmute callbacks are received in the target peer's HMSUpdateListener.onChangeTrackStateRequest.

The target peer will receive an object of HMSChangeTrackStateRequest.

Here's its structure.

data class HMSChangeTrackStateRequest( val track : HMSTrack, val requestedBy : HMSPeer, val mute : Boolean)

This contains information on which track is requested for unmuting. Check the track type and inform the user as appropriate.

fun checkTrack(track : HMSTrack) { if(track.type == HMSTrackType.AUDIO) { } else if (track.type == HMSTrackType.VIDEO) { } }

Hold onto the information here, show a dialog to the user to ask if they want to accept the change and then apply the settings locally. The same as in a regular user Mute/Unmute.

Multiple Peers or Tracks

Once you have checked that the caller has permissions to mute another peer's audio or video, call for it with hmsSdk.changeTrackState.

To mute audio for a multiple peers or tracks:

hmsSdk.changeTrackState takes five parameters:

  • mute: Boolean true if the track needs to be muted, false otherwise
  • type *HMSTrackType optional, the HMSTrackType which should be affected. If this and source** are specified, it is considered an AND operation. If null, all track sources are affected.
  • source Source optional, the [HMSTrackSource] which should be affected. If this and [type] are specified, it is considered an AND operation. If null, all track sources are affected.
  • roles List<HMSRole> optional, a list of roles, may have a single item in a list, whose tracks should be affected. If null, all roles are affected.
  • hmsActionResultListener HMSActionResultListener the callback that would be called by SDK in case of a success or failure.

Here's an example of how you would check if the caller was allowed to mute peers and then call for a mute/unmute on all peers in the chat.

fun remoteMute(mute: Boolean, roles: List<String>?) { if (isAllowedToMutePeers()) { val selectedRoles = if (roles == null) null else { hmsSdk.getRoles().filter { roles.contains(it.name) } } hmsSdk.changeTrackState( mute, null, null, selectedRoles, object: HMSActionResultListener { override fun onSuccess() { // Remote mute suceeded } override fun onError(error: HMSException) { // Error } }) } }

This can be further narrowed by specifying only those tracks of type Audio like so:

Note that HMSTrackSource.REGULAR is the peer's own audio and video as opposed to one provided by screenshare or a plugin.

hmsSdk.changeTrackState( true, HMSTrackType.AUDIO, HMSTrackSource.REGULAR, emptyList(), object : HMSActionResultListener { override fun onSuccess() { } override fun onError(error: HMSException) { } } )