Getting Started - JavaScript

Introduction

This guide provides an overview of the key objects you'll use with 100ms' JavaScript SDK to build a live audio/video application

If you haven't already done so, try our sample quickstartapp. Then you can come back later to see how to build your own live audio/video app in more detail

Supported Devices

Our alpha release has been tested on modern Chrome browsers. We will expand browser support to all modern browsers soon.

Basic Concepts

  • Room - A room represents a real-time audio, video session, the basic building block of the 100ms Video SDK
  • Track - A track represents either the audio or video that makes up a peer's stream
  • Peer - A peer represents all participants connected to a room. Peers can be "local" or "remote"
  • Broadcast - A local peer can send any message/data to all remote peers in the room

Pre-requisites

  1. Get the 100ms JS SDK
npm install --save @100mslive/hms-video@latest
  1. Get Access Keys: You can get your access keys in the Developer section of 100ms dashboard

  2. Create a room and setup a token generation service: To create a room, follow the steps described in this section. To setup a token generation service, follow the steps in this section. Alternatively, you can use our quickstart server for this.

Import modules & instantiate 100ms Client

import { HMSSdk } from '@100mslive/hms-video'; const hms = new HMSSdk();

Provide joining configuration, add listeners and join a room

const joinConfig = { userName: 'Erlich Bachmann', authToken: '<Auth token>', //This is the client-side token generated from your token service metaData: 'Custom description', //This is a custom data. You can send stringified JSON settings: { isAudioMuted: false, isVideoMuted: false } }; const listener = { onJoin(room) { // This will be called on a successful JOIN of the room by the user // This is the point where applications can stop showing its loading state // Parameter room: the room which was joined // For now, no events are sent to this callback. Leave this empty }, onRoomUpdate(type, room) { // This is called when there is a change in any property of the Room. This is an advanced use case // Parameters: // type: the triggered update type. Should be used to perform different UI Actions // room: the room which was joined // check the type tab to see all types }, onPeerUpdate(type, peer) { // This will be called whenever there is an update on an existing peer // or a new peer got added/existing peer is removed. // This callback can be used to keep a track of all the peers in the room // Parameters: // type: the triggered update type. Should be used to perform different UI Actions // peer: the peer who joined/left or was updated // .Usually a call to getPeers(), getLocalPeer() is needed here // check the type tab to see all types }, onTrackUpdate(type, track, peer) { // This is called when there are updates on an existing track // or a new track got added/existing track is removed // This callback can be used to render the video on screen whenever a track gets added // Parameters: // type: the triggered update type // track: the track which was added, removed or updated // peer: the peer for which track was added, removed or updated // Usually a call to getPeers(), getLocalPeer() is needed here // check the type tab to see all types }, onMessageReceived(message) { // This is called when there is a new broadcast message from any other peer in the room // This can be used to implement chat is the room // Parameter message: the received broadcast message }, onError(error) { // This will be called when there is an error in the system // and SDK has already retried to fix the error // Parameter error: the error that occured }, onReconnecting(error: HMSException) { // This is called when connection reestablishment starts // This can be used to show a loading notification in the UI // Parameter error: the error from the action that failed and caused the connection reestablishment }, onReconnected() { // This is called when the connection reestablishment completed susccessfully }, onDeviceChange(deviceMap: DeviceMap): void { // This is called once after join is called and everytime a device is either added or removed // The deviceMap contains a map of all the devices connected }, onRoleChangeRequest(request: HMSRoleChangeRequest): void { // This is called when a role change request is received from another user // Refer to the section involving changing roles mid-call below for more details } }; function onAudioLevelUpdate(speakers) { // This is a separate listener that will be updated for listening to audio levels // This is optional } hms.join(joinConfig, listener); hms.addAudioListener({ onAudioLevelUpdate: onAudioLevelUpdate });

Get peers/tracks data

const localPeer = hms.getLocalPeer(); const peers = hms.getPeers(); const localVideoTrack = localPeer.videoTrack;

Render video

All audio tracks are rendered automatically by the SDK. As the developer, you just need to render the video track

const localVideoTrack = localPeer.videoTrack; const videoElement = document.getElementById('local-video-id'); localVideoTrack.addSink(videoElement); //rendering code <video id="local-video-id" autoplay muted></video>;

Mute/unmute local tracks

await localVideoTrack.setEnabled(false); await localAudioTrack.setEnabled(false); //On unmuting video, call addSink again to render the video await localVideoTrack.setEnabled(true); localVideoTrack.addSink(videoElement);

Adjust remote peer volume

const remotePeer = hms.getPeers().filter((peer) => !peer.isLocal)[0]; const remoteAudioTrack = remotePeer.audioTrack; //mute remoteAudioTrack.setVolume(0); //unmute remoteAudioTrack.setVolume(100); // here we should probably use something between 0-100 remoteAudioTrack.setVolume(100); // Get volume remoteAudioTrack.getVolume();

Sharing screen

// Starting screenshare hms.startScreenShare(onStop); // onStop is the callback called if user stops the screenshare // from the system prompt // Stopping screenshare hms.stopScreenShare();

Sending and receiving messages

You can broadcase a message from local peer to all remote peers in the room.

When you(the local peer) receives a message from others(any remote peer), func onMessageReceived(message: HMSMessage) of listener passed at the time of join is invoked.

const message = "Hello World!" sdk.sendMessage(HMSMessageType.CHAT, message) function onMessageReceived(msg) { const sender = msg.sender; // peer id of sender const message = msg.message; // string message sent by remote }

Leave

hms.leave();

Managing roles

Roles define the permissions and the parameters for video, audio and screen of the users in the room.

The role of a user is attached to the HMSPeer object. Refer HMSRole interface in the next secion.

Changing roles mid-call

In order to change the role of a remote peer during the call, you can use the changeRole method provided by the SDK.

Initiating a role-change request

const roles: HMSRole[] = hms.getRoles(); // this returns a list of roles in the room const peers = hms.getPeers(); // later in your code /** * forPeer - HMSRemotePeer - The user whose role must be changed * newRole - String - The name of the new role * [force] - boolean - If true, the role change will be forced. false by default. */ hms.changeRole(forPeer, newRole, force);

The SDK will throw an error if the user requesting the role change does not have permission to change roles. You can check if the user has permission to change role by checking localPeer.permissions.changeRole

Accepting a role-change request

A user will receive role-change requests via the listener passed to join method.

In order to accept the request, call the acceptRoleChange method, passing the incoming request.

/** * request: HMSRoleChangeRequest - The role change request to be accepted */ hms.acceptChangeRole(request);

On successful role change, the onPeerUpdate event will be fired for all the users connected to the room. The type of update would be HMSPeerUpdate.ROLE_UPDATED and the updated peer would also be passed to this callback.

If the role change was forced, the user will not receive the request. Instead, onPeerUpdate will be fired for all the connected users and with modified role for the user concerned.

In case of unforced change, the user can choose to reject the role change request by ignoring the onRoleChangeRequest event i.e. take no action when the event is fired.

Advanced use cases

Showing a preview screen before joining

To display a preview of your local stream before joining the call, you can use the preview method provided by the SDK.

This method does NOT publish this video to the room. Publishing is handled via the join method.

const previewConfig = { userName: 'Erlich Bachmann', // If you choose to provide a name later, you can pass an empty string here authToken: '<Auth token>', //This is the client-side token generated from your token service settings: { isAudioMuted: false, isVideoMuted: false } }; const previewListener = { onPreview(room, localTracks) { // localTracks contains the video and audio tracks of the user // Inside this callback you are safe to access local peer const localPeer = hms.getLocalPeer(); const videoTrack = localPeer.videoTrack; videoTrack.addSink(document.getElementById('preview-video-id')); }, onError(exception) { // this will be called if there were any errors accessing user's camera or mic // or if there is network disconnection }, onDeviceChange(deviceMap: DeviceMap): void { // This is called once after preview is called and everytime a device is either added or removed // The deviceMap contains a map of all the devices connected } }; hms.preview(previewConfig, previewListener); hms.addAudioListener({ onAudioLevelUpdate: onAudioLevelUpdate }); <video id="preview-video-id" autoplay muted></video>;

You can use the track methods mentioned above to mute/unmute local tracks during preview.

Changing mic/camera before/during the call

//Changing before the call const joinConfig = { userName: 'Erlich Bachmann', authToken: '<Auth token>', //This is the client-side token generated from your token service metaData: 'Custom description', //This is a custom data. You can send stringified JSON settings: { isAudioMuted: false, isVideoMuted: false, audioInputDeviceId: 'default'; videoInputDeviceId: 'default'; }, }; hms.join(joinConfig, listener); //Changing midway during the call localVideoTrack.setSettings({deviceId:'default'});

Adding / removing auxiliary tracks

To add an auxiliary track(canvas capture, electron screen-share, etc...), you can use the addTrack method provided by the SDK. This method adds the track to the local peer's list of auxiliary tracks and publishes it to make it available to remote peers.

/** * track: MediaStreamTrack - Track to be added * source: 'regular' | 'screen' | 'plugin' - Source of track - default: 'regular' */ await hms.addTrack(track, source);

To remove an auxiliary track, you can use the removeTrack method provided by the SDK. This method removes the track from the local peer's list of auxiliary tracks and unpublishes it.

// trackId: ID of the track to be removed await hms.removeTrack(trackId);

removeTrack removes the track only from the list of auxiliary tracks of the local peer. It doesn't remove/unpublish the audioTrack/ videoTrack of the local peer.

Managing Audio Ouput

To customize the audio output device and volume, AudioOutputManager could be used.

const audioOutput = hms.getAudioOutput(); audioOutput.setDevice('a-device-id'); // deviceId of a valid MediaDeviceInfo const device = audioOutput.getDevice(); audioOutput.setVolume(95); const volume = audioOutput.getVolume();

To set the output volume of a particular audio track[HMSAudioTrack], use track.setVolume(95); and use track.getVolume(); to retrieve the current value.

Handling Autoplay

Most modern browsers don't allow audio to be played without any interaction. on Autoplay error, we throw an error in onError handler passed to join/preview with an error code 3008.

To unblock the autoplay error, use the following method on some UI interaction(eg: button click).

await hms.getAudioOutput().unblockAutoplay();

Setting Log Level

To set log level for logging only errors and warnings in production, use hms.setLogLevel.

import { HMSLogLevel } from '@100mslive/hms-video'; hms.setLogLevel(HMSLogLevel.WARN); // Log warnings and errors hms.setLogLevel(HMSLogLevel.ERROR); // Log only errors
enum HMSLogLevel { VERBOSE, DEBUG, INFO, WARN, ERROR, NONE, }