Video Call Integration in SAP UI5

Preface – This post is part of the UI5 Integration Programs series.

Introduction

Video call is a feature that allows two or more people to communicate with each other using real-time video and audio transmissions over the internet. It allows people to connect and interact with each other, regardless of their physical location, by transmitting live video and audio signals through a digital network.

Video calls can be made using a variety of devices, such as smartphones, tablets, laptops, desktop computers, and specialized video conferencing equipment. To make a video call, both parties must have compatible devices and access to the internet, either through Wi-Fi or mobile data.

During a video call, the camera on each device captures live video of the person or people on the other end of the call, which is then transmitted over the internet to the other device. Similarly, the microphone on each device captures the audio of the person speaking, which is also transmitted over the internet to the other device.

Video calling has become increasingly popular in recent years, as it provides a more personal and engaging way to communicate than traditional phone calls or text-based messaging. It’s often used for personal communication between family and friends, as well as for professional purposes such as virtual meetings, job interviews, and remote work collaboration.

What is a video calling feature in a Web application?

A video calling feature in a web application is a software functionality that allows users to initiate and participate in live video calls directly within a web browser. It enables people to have real-time audio and video communication through their desktop, laptop, or mobile device without the need for any additional software or hardware.

To use the video calling feature in a web application, users typically need a compatible web browser, a webcam, a microphone, and a stable internet connection. Once the user has these components set up, they can initiate or join a video call with another user or a group of users in the web application.

Web-based video calling is often integrated with other communication features such as instant messaging, screen sharing, and file sharing. It is commonly used for virtual meetings, remote work collaboration, online learning, and social communication.

Web-based video calling can be done using various web technologies, including WebRTC (Web Real-Time Communication), which is an open-source project that enables real-time communication between browsers, and other proprietary solutions. Some popular examples of web-based video calling platforms include Zoom, Google Meet, Microsoft Teams, and Skype.

What all ways can we integrate video calling feature in a Web Application?

There are various ways to integrate a video calling feature in a web application, some of which include:

  1. WebRTC: WebRTC (Web Real-Time Communication) is a free, open-source project that enables real-time communication between browsers. It provides the necessary APIs for web developers to implement video calling directly in their web applications, without requiring additional software or plugins.
  2. Using third-party APIs and SDKs: Many video calling platforms, such as Zoom, Google Meet, and Twilio, provide APIs and SDKs that developers can use to integrate video calling features into their web applications.
  3. Building a custom solution: Developers can build a custom solution for video calling by leveraging various web technologies such as WebSockets, Node.js, and socket.io. This requires extensive development and testing but allows for greater customization and control over the video calling experience.
  4. Using a pre-built solution: There are also pre-built video calling solutions available that can be easily integrated into web applications, such as Agora.io, Vonage Video API, and Daily.co. These solutions typically offer a range of features, including screen sharing, recording, and chat, and can be customized to fit the specific needs of a web application.

The choice of integration method will depend on factors such as the level of customization required, the budget and resources available, and the specific features needed for the web application.

What is the concept of WebRTC API?

WebRTC (Web Real-Time Communication) is a free, open-source project that enables real-time communication between browsers and mobile applications. It provides a set of JavaScript APIs that allow developers to integrate real-time communication capabilities, such as video and audio calling, directly into their web applications without requiring any additional software or plugins.

WebRTC’s core components include:

  1. getUserMedia: This API allows web applications to access a user’s camera and microphone, enabling them to capture audio and video data.
  2. RTCPeerConnection: This API allows web applications to establish a peer-to-peer connection between browsers or mobile devices, enabling real-time communication of audio and video data.
  3. RTCDataChannel: This API allows web applications to create a bi-directional, low-latency communication channel for sending arbitrary data between peers.

Together, these APIs form the basis of WebRTC and enable developers to build real-time communication features directly into their web applications. WebRTC is supported by all major browsers, including Google Chrome, Mozilla Firefox, Apple Safari, and Microsoft Edge, and is used for a variety of applications, including video conferencing, voice calling, and file sharing.

WebRTC also offers a secure, end-to-end encrypted communication channel, ensuring that user data is protected during transmission. Because it’s an open-source project, WebRTC is constantly evolving, and new features and functionalities are being added all the time.

Video Integration using Agora Web SDK

Agora Web SDK is a software development kit that enables developers to integrate real-time video and audio communication into their web applications. Here’s how to integrate video using Agora Web SDK:

  1. Create an Agora developer account and generate an App ID: To use Agora Web SDK, you need to create an account on the Agora platform and generate an App ID, which is used to authenticate your application and enable access to the Agora services.
    Agora Video CallingOur goal here is to create a project within Agora and get App ID, Channel and Token. In our usecase, we have got these:

    App ID: 09ed05f4f81d4ec580c45277ab70dac5
    Channel: ui5Demo
    Token: 007eJxTYND+53eO3bl+x9yax6cU1HLqHHZKN/5+f2LLwvXr/s9Luu6vwGBgmZpiYJpmkmZhmGKSmmxqYZBsYmpkbp6YZG6QkphsOvXN++SGQEaGo1P+MzMyQCCIz85Qmmnqkpqbz8AAAJQWJIA=

     

  2. Add the Agora Web SDK to your project: Once you have an App ID, you can add the Agora Web SDK to your project by including the Agora JavaScript library in your HTML code.
    These are the script for that:

    <!-- Agora Scripts -->
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script src="https://download.agora.io/sdk/release/AgoraRTC_N.js"></script>

     

  3. Initialize the Agora client: The next step is to initialize the Agora client in your JavaScript code using the App ID and other necessary parameters.
  4. Create a video call: To create a video call, you need to create a video call object that contains the necessary configuration parameters, such as the channel name, mode, and codec. Then, you can join the call by calling the Agora RTC client join method.
  5. Manage the video call: Once the call is established, you can use the Agora SDK to manage the call, including starting and stopping video streams, muting and unmuting audio, and sharing the screen.
  6. Clean up: Finally, when the call is complete, you can use the Agora SDK to release the resources and terminate the call.

Agora Web SDK provides a range of additional features and functionalities, including the ability to customize the user interface, integrate with third-party services, and control the quality of service. By integrating video using Agora Web SDK, you can add real-time communication capabilities to your web application, enabling users to connect with each other in a more immersive and engaging way.

How to integrate Video Calling feature in SAP UI5?

To Integrate a Video calling in SAP UI5, we will 3rd party API of Agora and the concept of WebRTC API. Please find the respective code below:

HTML Code:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <!--<meta name="viewport" content="width=device-width, initial-scale=1.0">-->
        <title>My Project Ideas</title>
         <link rel="icon" type="image/x-icon" href="https://myprojectideas.com/wp-content/uploads/2021/08/cropped-Screenshot-2021-07-26-at-1.39.04-PM-32x32.png">
        <script id="sap-ui-bootstrap"
            src="resources/sap-ui-core.js"
            data-sap-ui-theme="sap_fiori_3"
            data-sap-ui-resourceroots='{"Test.Test": "./"}'
            data-sap-ui-compatVersion="edge"
            data-sap-ui-oninit="module:sap/ui/core/ComponentSupport"
            data-sap-ui-async="true"
            data-sap-ui-frameOptions="trusted">
        </script>
          <!-- Agora Scripts -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://download.agora.io/sdk/release/AgoraRTC_N.js"></script>
    </head>
    <body class="sapUiBody">
        <div data-sap-ui-component data-name="Test.Test" data-id="container" data-settings='{"id" : "Test"}'></div>
    </body>
</html>

View Code:

<mvc:View controllerName="Test.Test.controller.Main" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m" xmlns:core="sap.ui.core"
    xmlns:html="http://www.w3.org/1999/xhtml">
    <Shell id="shell">
        <App id="app">
            <pages>
                <Page id="page" title="Video Call Integration in SAP UI5">
                    <content>
                        <core:HTML class="sapUiLargeMargin"
                            content='&lt;div class=&quot;container&quot;&gt; &lt;div class=&quot;participant&quot; id=&quot;participant&quot;&gt;&lt;/div&gt; &lt;div class=&quot;fs&quot; id=&quot;fs&quot;&gt;&lt;/div&gt; &lt;/div&gt;'></core:HTML>
                    </content>
                    <footer >
                        <OverflowToolbar>
                            <Button id="idRemaining" type="Emphasized"/>
                            <ToolbarSpacer/>
                            <Button icon="sap-icon://popup-window" class="sapUiTinyMarginBeginEnd" text="Share Screen" press="onShareScreen"/>
                            <Button id="idMute" icon="sap-icon://sound-off" class="sapUiTinyMarginEnd" text="Mute" press="onPressMute"/>
                            <Button id="idUnmute" visible="false" class="sapUiTinyMarginEnd" icon="sap-icon://sound-loud" text="Unmute" press="onPressUnmute"/>
                            <Button type="Reject" text="Close Call" press="closeCall">
                                <layoutData><OverflowToolbarLayoutData priority="NeverOverflow"/></layoutData>
                            </Button>
                        </OverflowToolbar>
                    </footer>
                </Page>
            </pages>
        </App>
    </Shell>
</mvc:View>

Controller Code:

sap.ui.define([
    "sap/ui/core/mvc/Controller",
    "sap/m/MessageBox",
    "sap/m/MessageToast"
], function (Controller, MessageBox, MessageToast) {
    "use strict";

    return Controller.extend("Test.Test.controller.Main", {
        onAfterRendering: async function (evt) {
            var that = this;
            this.flag = 0;
            try {
                var that = this;
                var date = new Date();
                var startTime = date.getTime();
                this.appointmentURL = {
                    startTime: startTime,
                    channel: "ui5Demo",
                    token: "007eJxTYND+53eO3bl+x9yax6cU1HLqHHZKN/5+f2LLwvXr/s9Luu6vwGBgmZpiYJpmkmZhmGKSmmxqYZBsYmpkbp6YZG6QkphsOvXN++SGQEaGo1P+MzMyQCCIz85Qmmnqkpqbz8AAAJQWJIA="
                };
                this.timeOut = setInterval(function () {
                that.alertFunc()
                }.bind(that), 1000);
                that.rtc = {
                    // For the local audio and video tracks.
                    localAudioTrack: null,
                    localVideoTrack: null,
                };
                if (this.appointmentURL) {
                    var options = {
                        // Pass your app ID here.
                        appId: "09ed05f4f81d4ec580c45277ab70dac5",
                        // Set the channel name.
                        channel: this.appointmentURL.channel,
                        // Set the user role in the channel.
                        role: "host"
                    };
                    var token = this.appointmentURL.token;
                }
                that.client = AgoraRTC.createClient({
                    mode: "rtc",
                    codec: "vp8"
                });
                var uid = "doctor";
                var div = document.createElement("div");
                div.id = uid;
                div.className = "zoomOut"
                that.client.on("user-left", async(user, mediaType) => {
                    var elem = document.getElementById("id" + user.uid);
                    elem.parentElement.removeChild(elem);
                    console.log("left");
                });
                that.client.on("user-published", async(user, mediaType) => {
                    await that.client.subscribe(user, mediaType);
                    console.log("subscribe success");
                    var uuid = "id" + user.uid;
                    if (document.getElementById(uuid) == undefined) {
                        var div = document.createElement("div");
                        div.id = uuid;
                        if (that.flag === 0) {
                            div.className = "zoomIn"
                        } else {
                            div.className = "zoomOut"
                        }
                        that.buttonUID = uuid;
                        var button = document.createElement("button");
                        if (that.flag === 0) {
                            button.innerHTML = "Unpin";
                        } else {
                            button.innerHTML = "Pin";
                        }
                        button.className = "zoomButton";
                        that.flag = 1;
                        button.addEventListener("click", function (oEvent) {
                            var a = document.getElementById(uuid).className;
                            if (a == "zoomOut") {
                                if (document.getElementsByClassName("zoomIn").length > 0) {
                                    document.getElementsByClassName("zoomIn")[0].className = "zoomOut";
                                }
                                document.getElementById(uuid).className = "zoomIn";
                                oEvent.currentTarget.innerHTML = "Unpin";
                                var allButtons = document.getElementsByClassName("zoomOut");
                                for (var i = 1; i < allButtons.length; i++) {
                                    var reqButton = allButtons[i].getElementsByClassName("zoomButton");
                                    if (reqButton.length > 0) {
                                        reqButton[0].style.display = "none";
                                    }
                                }
                            } else {
                                document.getElementById(uuid).className = "zoomOut";
                                oEvent.currentTarget.innerHTML = "Pin";
                                var allButtons = document.getElementsByClassName("zoomOut");
                                for (var i = 1; i < allButtons.length; i++) {
                                    var reqButton = allButtons[i].getElementsByClassName("zoomButton");
                                    if (reqButton.length > 0) {
                                        reqButton[0].style.display = "block";
                                    }
                                }
                            }

                        });
                        div.appendChild(button);
                        document.getElementById("participant").appendChild(div);
                    }
                    const remoteVideoTrack = user.videoTrack;
                    that.remotePlayerContainer = document.getElementById(uuid);
                    remoteVideoTrack.play(that.remotePlayerContainer);
                    if (mediaType === "audio") {
                        const remoteAudioTrack = user.audioTrack;
                        remoteAudioTrack.play();
                    }

                });
                document.getElementById("participant").appendChild(div);
                // that.client.setClientRole(options.role);
                await that.client.join(options.appId, options.channel, token, 0);
                that.rtc.localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack();
                that.rtc.localVideoTrack = await AgoraRTC.createCameraVideoTrack();
                await that.client.publish([that.rtc.localAudioTrack, that.rtc.localVideoTrack]);
                that.localPlayerContainer = document.getElementById(uid);
                that.rtc.localVideoTrack.play(that.localPlayerContainer);
                // Users joins for the first time

            } catch (error) {
                console.log(error);
                var errorMessage;
                // Handle Errors here.
                if (error && error.message) {
                    errorMessage = error.message;
                    if (error.code == 'CAN_NOT_GET_GATEWAY_SERVER') {
                        errorMessage = "The meeting session is no longer valid. Contact Admin";
                    }
                } else {
                    errorMessage = "Something went wrong, contact Admin if the error persists";
                }
                MessageBox.error(errorMessage, {
                    actions: [MessageBox.Action.CLOSE],
                    onClose: function (sAction) {
                        if (sAction == 'CLOSE') {
                            // Write close operation
                        }
                    }
                });
            };
        },

        onCancelCall: function (oEvent) {
            this.closeCall();
        },

        onMarkCompleteCall: function (oEvent) {
            this.closeCall();
        },

        closeCall: async function (oEvent) {
            var that = this;
            var date = new Date();
            var endTime = date.getTime();
            if (that.rtc) {
                that.rtc.localAudioTrack.close();
                // that.rtc.localVideoTrack.stop();
                that.rtc.localVideoTrack.close();
                // Traverse all remote users.
                // Destroy the dynamically created DIV containers.
                const playerContainer = document.getElementById('div2');
                playerContainer && playerContainer.remove();
                // Leave the channel.
                await that.client.leave();
            }
        },

        alertFunc: function () {
            var that = this;
            var countDownDate = that.appointmentURL.startTime;
            // Get today's date and time
            var now = new Date().getTime();
            var endTime = "10-22-05";
            // Find the distance between now and the count down date
            var distance = now - countDownDate;

            // Time calculations for days, hours, minutes and seconds
            var hours = that.doubleDigit(Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)));
            var minutes = that.doubleDigit(Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)));
            var seconds = that.doubleDigit(Math.floor((distance % (1000 * 60)) / 1000));
            var timeRemaining =
                new Date('01/01/2007 ' + endTime.split('-')[1] + ':00').getTime() -
                new Date('01/01/2007 ' + endTime.split('-')[0] + ':00').getTime();
            var diff = Math.abs(
                Math.floor((timeRemaining % (1000 * 60 * 60)) / (1000 * 60)),
            );

            that.getView().byId("idRemaining").setText(hours + ':' + minutes + ':' + seconds);
            if (minutes > diff) {
                that.getView().byId("idRemaining").setType("Critical");
            }
        },

        doubleDigit: function (time) {
            return ("0" + time).slice(-2);
        },

        onShareScreen: async function (oEvent) {
            var that = this;
            if (this.appointmentURL) {
                var appId = "09ed05f4f81d4ec580c45277ab70dac5";
                var channel = this.appointmentURL.channel;
                var token = this.appointmentURL.token;
            }
            const screenClient = AgoraRTC.createClient({
                mode: "rtc",
                codec: "vp8"
            });
            await screenClient.join(appId, channel, token);
            const screenTrack = await AgoraRTC.createScreenVideoTrack();
            await screenClient.publish(screenTrack);
            return screenClient;
        },

        onPressMute: function (oEvent) {
            this.byId("idMute").setVisible(false);
            this.byId("idUnmute").setVisible(true);
            this.rtc.localAudioTrack.setEnabled(false);
        },

        onPressUnmute: function (oEvent) {
            this.byId("idMute").setVisible(true);
            this.byId("idUnmute").setVisible(false);
            this.rtc.localAudioTrack.setEnabled(true);
        },

        onPressZoomIn: function (oEvent) {
            var divID = oEvent.getSource().data("divID");
            document.getElementById(divID).style.width = "640px";
            document.getElementById(divID).style.height = "480px";
        },

        onPressZoomOut: function (oEvent) {
            var divID = oEvent.getSource().data("divID");
            document.getElementById(divID).style.width = "320px";
            document.getElementById(divID).style.height = "240px";
        }
    });
});

 

CSS Code:

/* Enter your custom styles here */
.EmphasizedText {
    font-weight: bold;
    -webkit-text-fill-color: #085caf;
}

.whitebg {
    background-color: white !important;
}

.container {
    display: flex;
}

.participant {
    width: 20%;
    height: 500px;
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
   
}

.zoomOut {
    width: 80%;
    height: 200px;
    position: relative;
}

.fs {
    width: 80%;
    display: flex;
    align-items: center;
}

.zoomButton {
    position: absolute;
    z-index: 100;
    top: 5px;
    right: 5px;
    border-color: #fff;
    background: #fff;
    color: black;
}

.zoomButton:before {
    content: "📌 ";
}

.zoomIn {
    width: 80%;
    height: 100%;
    position: absolute;
    right: 10px;
}

html.sap-desktop .sapMShellAppWidthLimited .sapMShellCentralBox {
    width: 100% !important;
    margin-left: 5px !important;
    left: 0 !important;
}

Output

Video Call Integration in SAP UI5

Author

  • Barry Allen

    A Full Stack Developer with 10+ years of experience in different domain including SAP, Blockchain, AI and Web Development.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.