Sceenic Plugin for Web

Getting started

๐Ÿšง

Minimum supported engagement SDK

Web engagement SDK version: 2.24.0

๐Ÿ“˜

API documentation

Refer sceenic-plugin API documentation for more details

Install the sceenic plugin:

Install sceenic plugin from npm registry. Sceenic plugin is published in 3 variants:

  1. ES module (livelike-sceenic-plugin.min.js)
  2. Common JS (livelike-sceenic-plugin.cjs.js)
  3. UMD (livelike-sceenic-plugin.umd.js)

When installed using npm, the ES module variant is been used. To use umd bundle refer below html snippet

npm install @livelike/sceenic-plugin
<script src="https://unpkg.com/@livelike/sceenic-plugin/livelike-sceenic-plugin.umd.js"></script>

To install a specific version of sceenic-plugin

npm install @livelike/[email protected]

Initialise the sceenic plugin:

Initialise the sceenic plugin passing the livelike API provider

๐Ÿšง

Initialise web engagement sdk

Make sure to initialise web engagement sdk with the procured client id, refer web sdk getting started for more details

๐Ÿ“˜

Code snippet variations

ES Module: code snippet when integrating using ES module
HTML UMD: code snippet when integrating using UMD sceenic-plugin bundle

import LiveLike from '@livelike/engagementsdk';
import { init } from '@livelike/sceenic-plugin';

init({
    liveLikeApiProvider: LiveLike
}).then((pluginInstance) => {
// post sceenic plugin initialisation logic
});

// Also initialise livelike web sdk
LiveLike.init({
    clientId: "<your clientId>"
}).then((userprofile) => {
// post web engagement sdk initialisation logic
});
<script>
// make sure to include livelike umd script as well which would 
// expose `LiveLike` reference on window object
LiveLikeSceenicPlugin.init({
    liveLikeApiProvider: window.LiveLike
}).then((pluginInstance) => {
// post sceenic plugin initialisation logic
});

window.LiveLike.init({
    clientId: "<your clientId>"
}).then((userprofile) => {
// post initialisation logic
})
</script>

Render sceenic-video-room:

sceenic-video-room is a web component which could be used for a seamless integration which gives pre-baked functionality of:

  • creating a video room
  • joining a video room
  • rendering participant videos
  • leaving a video room
  • mute/unmute local participant audio
  • show/hide local participant video
<body>
    <sceenic-video-room></sceenic-video-room>
</body>

sceenic-video-room web component properties:

Property nameDescription
aspectratioSet aspect ratio of the participant video (default is 4/3)
minvideowidthSet minimum video width of each participant (default is auto calculated based on parent container of sceenic-video-room)
minvideoheightSet minimum video height of each participant (default is auto calculated based on parent container of sceenic-video-room)
<body>
<sceenic-video-room
    aspectratio=1.7778
    minvideowidth=150
    minvideoheight=84 
>
</sceenic-video-room>
</body>

Customise sceenic-video-room:

When there is a need to customise sceenic-video-room stock UI, extend SceenicVideoRoom Web component class and custom render parts of stock UI based on your level of customisation.

For example, customising session entry controls

// use html API from sceenic-plugin to create lit template 
// https://lit.dev/docs/v1/lit-html/writing-templates/
import { SceenicVideoRoom, html } from '@livelike/sceenic-plugin";

class CustomSceenicVideoRoom extends SceenicVideoRoom {
    renderSessionEntryControls() {
        return html`
          <div>
          <div class="session-entry">
              <button
                id="create-call-control"
                class="control-button my-test"
                title="Create Video Room"
                @click=${this.createVideoRoom}
                style="color: white;"
              >
                Create
              </button>
              <div class="join-control">
                <input id="video-room-id" type="text" placeholder="Video Room Id" />
                <button
                  class="control-button join-control-button"
                  title="Join Video Room"
                  @click=${this.joinVideoRoom}
                  style="color: white;"
                >
                    Join
                </button>
              </div>
            </div>
            <p style="color: red;">Sponsored by: Livelike</p>
            </div>
          `;
    }
}

if (!customElements.get("custom-sceenic-video-room")) {
  customElements.define("custom-sceenic-video-room", CustomSceenicVideoRoom);
}
<script>
class CustomSceenicVideoRoom extends LiveLikeSceenicPlugin.SceenicVideoRoom {
    renderSessionEntryControls() {
        return LiveLikeSceenicPlugin.html`
          <div>
          <div class="session-entry">
              <button
                id="create-call-control"
                class="control-button my-test"
                title="Create Video Room"
                @click=${this.createVideoRoom}
                style="color: white;"
              >
                Create
              </button>
              <div class="join-control">
                <input id="video-room-id" type="text" placeholder="Video Room Id" />
                <button
                  class="control-button join-control-button"
                  title="Join Video Room"
                  @click=${this.joinVideoRoom}
                  style="color: white;"
                >
                    Join
                </button>
              </div>
            </div>
            <p style="color: red;">Sponsored by: Livelike</p>
            </div>
          `;
    }
}

  if (!customElements.get("custom-sceenic-video-room")) {
    customElements.define("custom-sceenic-video-room", CustomSceenicVideoRoom);
  }
</script>

Implement Custom UI:

In case, you want to integrate sceenic-plugin in UI frameworks like React, Angular, Vue.js etc. this would require you to implement custom UI based on framework API's.
This could be achieved with the use of plugin instance - service, model and serviceProvider.

What is Plugin instance?

Plugin instance is an object which could be used to implement video room features in any JS framework with the following properties:

const { service, model, serviceProvider } = pluginInstance;

1. service - reference to plugin service which contains actions API to create, join and manage a video room session.

1. createVideoRoom() - To create and join a new video room session 
2. joinVideoRoom(videoRoomId) - To join an existing video room using a given video id
3. enableAudio(status): Enable/Disable mic audio
4. enableVideo(status): Enable/Disable local user video
5. leaveVideoRoom() - Leave the joined video room
6. addVideoRoomEventListener(VideoRoomEvent, listenerFn): Add custom use cases in the form of listener fn which gets invoked based on given sceenic event.
7. removeVideoRoomEventListener(VideoRoomEvent, listenerFn): remove attached listener function

2. serviceProvider - reference of underlying service provider, incase you want to directly use third part service client for your custom use cases.

Refer sceenic documentation for more details on sceenic serviceProvider.

3. model - reference to service model instance (similar to reactive UI state) which maintains a video room session data:

1. getData() - returns the current model data
2. setData(modelData) - to set the model data which internally publishes to all the model subscribers
3. subscribe(subscriberFn) - subscribe to the reactive model data where the subscriber function is called whenever model data gets changed.

Model data object properties:

Property NameProperty Description
audioEnabledflag to check whether local user audio is enabled or disabled. (type boolean, default true)
videoEnabledflag to check whether local user video is enabled or disabled. (type boolean, default true)
participantsArray of participants videos (type ISceenicParticipant, default empty array)
videoRoomIdvideo room identifier which could be used by other user to join an existing video room(type string, default undefined)
connectionStatusVideo room connection state of value - "CONNECTED" | "DISCONNECTED".
Initially it is "DISCONNECTED" until user creates or joins a video room post which connectionStatus changes to "CONNECTED".

How to get plugin instance?

There's two ways to get plugin instance:

1. Initialising sceenic-plugin returns a promise whose resolved value is a plugin instance.

import { init } from '@livelike/sceenic-plugin';
 
init({
    liveLikeApiProvider: window.LiveLike
}).then(pluginInstance => {
    const { service, model, serviceProvider } = pluginInstance; 
})
<script>
LiveLikeSceenicPlugin.init({
    liveLikeApiProvider: window.LiveLike
}).then(pluginInstance => {
   const {service, model, serviceProvider} = pluginInstance
});
</script>

2. addPluginEventListener:

listener for event PluginEvent.PLUGIN_INITIALISED get called with plugin instance. This could be used incase your init work flow is different then the UI component for eg: init is done during script loading which lazily loads application UI component where maintaining and passing plugin instance to lazily loaded UI component could result in unnecessary complexity.

import { addPluginEventListener, PluginEvent } from '@livelike/sceenic-plugin';

function onPluginInitialised(pluginInstance){
    const {service, model, serviceProvider} = pluginInstance
    //use service actions like create, join, leave or subsscribe to model
}

addPluginEventListener(
    PluginEvent.PLUGIN_INITIALISED,
    onPluginInitialised
)
<script>
  function onPluginInitialised(pluginInstance){
    const {service, model, serviceProvider} = pluginInstance
    //use service actions like create, join, leave or subsscribe to model
}

LiveLikeSceenicPlugin.addPluginEventListener(
    LiveLikeSceenicPlugin.PluginEvent.PLUGIN_INITIALISED,
    onPluginInitialised
)
</script>

๐Ÿ“˜

React.js sample code for Custom UI

Refer custom UI implementation for React.js framework using plugin instance.
Note: Update web engagement sdk initialisation with procured clientId in code sample

Video call feature implementation in native JS

Render Participant videos:

Subscribe to model data using pluginInstance.model.subscribe which would give you list of participant video.

function renderParticipantVideo({ local, stream, participantId }){
    const node = document.getElementById(participantId);

    if(node) {
        node.srcObject = stream;
    } else {
        const div = document.createElement("div")
        div.setAttribute("class", "video-container");

        const video = document.createElement("video");
        video.id = participantId;
        video.className = local ? "local" : "";
        video.autoplay = true;
        video.muted = local;
        video.srcObject = stream;
        video.playsInline = true;
        video.disablePictureInPicture = true;

        div.appendChild(video)

        const container = document.querySelector("#gallery");
        container.appendChild(div);
    }
}

function removeParticipantVideos(participants){
   const participantIds = participants.map(({participantId}) => participantId);
   const videoElements = Array.from(document.querySelectorAll('#gallery video'));
   videoElements
   .filter(videoEl => !participantIds.includes(videoEl.id))
   .map(videoEl => {
        videoEl.parentElement.remove();
   })
}

function modelsubscriber(modelData){
    const {participants} = modelData;
    // remove older participants videos
    removeParticipantVideos(participants);
    // render current participants videos
    participants.map(renderParticipantVideo)
}

// using reference of pluginInstance
const unsubscribe = pluginInstance.model.subscribe(modelsubscriber);
// unsubscribe when UI unmounts

Create a video room:

To create a video room, get the plugin instance service reference and call createVideoRoom method.
Below snippet assumes button with id create-button-id already present in html.

const createButton = document.querySelector('#create-button-id')

createButton.addEventListener('click', function (){
   // using reference of pluginInstance
    pluginInstance.service.createVideoRoom();
})

// Render participant videos (refer "Render Participant videos" docs)

Join a video room:

For joining a video room, one needs a video room id. Get the plugin instance service reference and call joinVideoRoom method which takes a video room ID and an optional participant Name as string.
Below snippet assumes button with id join-button-id already present in html.

const joinButton = document.querySelector('#join-button-id')

joinButton.addEventListener('click', function (){
    // using reference of pluginInstance
    pluginInstance.service.joinVideoRoom('ca62dae2-3901-40d5-bc2d-ad53a223689e');
})

// Render participant videos (refer "Render Participant videos" docs)

Leave a video room:

To leave a video room, get the plugin instance service reference and call leaveVideoRoom method which lets participant leave the currently joined video room.
Below snippet assumes button with id leave-button-id already present in html.

const leaveButton = document.querySelector('#leave-button-id')

leaveButton.addEventListener('click', function (){
    // using reference of pluginInstance
    pluginInstance.service.leaveVideoRoom();
})

// Render participant videos (refer "Render Participant videos" docs)

Video Room Event:

๐Ÿ“˜

Override sceenic callbacks

To override complete behaviour of participant add and participant left logic, refer Sceenic docs

In case thereโ€™s any custom UI requirement for eg: adding a banner whenever user join/leave a video room, you could attach an event listener and add your own custom logic.

VideoRoomEvent.PARTICIPANT_JOIN

Attach a listener to add custom logic whenever a participant joins a video call

function onParticipantJoin(participant){
   // custom logic
}
// using reference of pluginInstance
pluginInstance.service.addVideoRoomEventListener(LiveLikeSceenicPlugin.VideoRoomEvent.PARTICIPANT_JOIN, onParticipantJoin)

// To remove the attached listener
pluginInstance.service.removeVideoRoomEventListener(LiveLikeSceenicPlugin.VideoRoomEvent.PARTICIPANT_JOIN, onParticipantJoin)

VideoRoomEvent.PARTICIPANT_LEFT

Attach a listener to add custom logic whenever a participant leaves a video call

function onParticipantLeft(participant){
   // custom logic
}
// using reference of pluginInstance
pluginInstance.service.addVideoRoomEventListener(LiveLikeSceenicPlugin.VideoRoomEvent.PARTICIPANT_LEFT, onParticipantLeft)

// To remove the attached listener
pluginInstance.service.removeVideoRoomEventListener(LiveLikeSceenicPlugin.VideoRoomEvent.PARTICIPANT_LEFT, onParticipantLeft)

VideoRoomEvent.ERROR

Attach a listener to add custom logic whenever a video room or video session related error occurs for eg: error when network disconnected, max participant limit reached, expired video session, etc.

function onError(errorDetails){
   // custom logic
}
// using reference of pluginInstance
pluginInstance.service.addVideoRoomEventListener(LiveLikeSceenicPlugin.VideoRoomEvent.ERROR, onError)

// To remove the attached listener
pluginInstance.service.removeVideoRoomEventListener(LiveLikeSceenicPlugin.VideoRoomEvent.ERROR, onError)

VideoRoomEvent.RECONNECTING

Attach a listener to add custom logic whenever a user video session is reconnecting for eg: showing a reconnecting banner or showing alternate UI while reconnecting. You can subscribe to service model data which would give you the latest state of connectionStatus.

function onReconnecting(){
   // custom logic
}
// using reference of pluginInstance
pluginInstance.service.addVideoRoomEventListener(LiveLikeSceenicPlugin.VideoRoomEvent.RECONNECTING, onReconnecting)

// To remove the attached listener
pluginInstance.service.removeVideoRoomEventListener(LiveLikeSceenicPlugin.VideoRoomEvent.RECONNECTING, onReconnecting)