Eagle 3D Streaming

Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 8 Next »

This is a forked and tweaked version of Embed Streaming into a Webpage (no iframe solution) for a streaming UI implementation using react library.
Method 2 of this document can be used without changing the source code of the target application. By simply using the server provided in this doc, we can achieve single use token system.

Repo:
https://github.com/e3ds/full-html-control/tree/reactJs


For this tutorial, you must use this Control Panel for now.

This document describes guidelines on how to use the E3DS core library for a frontend application to stream a UE app inside the web application. To make the system work one must have an account in the E3DS platform, upload a UE app, and create a configuration in the control panel.

Method 1: Manually add token before accessing the stream

Let’s create a react app using create-react-app cli.

npx create-react-app streaming-ui --template typescript

After this completes, we will take a look at the index.html in the public folder.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico"/>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <meta name="theme-color" content="#000000"/>
    <meta name="description" content="Web site created using create-react-app"/>
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png"/>
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json"/>
    <title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>

We can either remove the things that aren’t needed or leave it as is.

Now we are going to put the script e3dsCore.min.js provided by E3DS into the public/scripts folder. We move on to connecting to our index.html file now. With inserting our script inside the head tag, the index.html becomes the following:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico"/>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <meta name="theme-color" content="#000000"/>
    <meta name="description" content="Web site created using create-react-app"/>
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png"/>
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json"/>
    <title>React App</title>
    <script type="text/javascript" src="scripts/e3dsCore.min.js"></script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>

However, nothing will happen. To intilaize the process you need to call a function main() which can be referenced by e3ds_controller object produced by e3dsCore.min.js file.

e3ds_controller.main(e3ds_session_token, clientUserName)

We will call it inside window.onload() https://www.w3schools.com/jsref/event_onload.asp. With inserting our script inside the head tag, our html becomes the following:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico"/>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <meta name="theme-color" content="#000000"/>
    <meta name="description" content="Web site created using create-react-app"/>
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png"/>
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json"/>
    <title>React App</title>
    <script type="text/javascript" src="scripts/e3dsCore.min.js"></script>
    <script>
        window.onload = function () {
            e3ds_controller.main()
        }
    </script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>

We will get invalid e3ds_session_token error which indicates that we forgot to provide a token.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico"/>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <meta name="theme-color" content="#000000"/>
    <meta name="description" content="Web site created using create-react-app"/>
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png"/>
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json"/>
    <title>React App</title>
    <script type="text/javascript" src="scripts/e3dsCore.min.js"></script>
    <script>
        window.onload = function () {
            e3ds_controller.main("myToken")
        }
    </script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>

We need to provide username too. Otherwise we’ll get the invalid clientUserName error.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico"/>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <meta name="theme-color" content="#000000"/>
    <meta name="description" content="Web site created using create-react-app"/>
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png"/>
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json"/>
    <title>React App</title>
    <script type="text/javascript" src="scripts/e3dsCore.min.js"></script>
    <script>
        window.onload = function () {
            e3ds_controller.main("myToken", "myUserName")
        }
    </script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>

This token was not found because system doesn't have any reference which indicates that this token was created via the system.

We need to generate a token here, and to make this token work with our present task, we have to generate it against a specific payload, which has to be a JSON object. For our task's purpose, this payload has to have at least these fields:

{
  "core": {
    "domain": "streaming domain",
    "userName": "clientUserName",
    "appName": "App available in your control panel",
    "configurationName": "config available in your control panel"
  }
}

userName: the username for which it will stream
appName: the name of the app that will stream
configurationName: the name of the configuration in the control panel with which the app will stream

To make things more clear, let's grab all those pieces of information from a working version of the streaming URL. Here, for the purpose of this tutorial, I will be using a URL from Eagle 3D’s account. In your case, you have to use a URL from your own account.

First, I made sure that this URL works and streams without any issues: https://connector.eagle3dstreaming.com/v5/demo/E3DSFeaturesTemplate/E3DS-Iframe-Demo.

If we can construct a payload object for token generation based on that URL, then it will be like this: https://connector.eagle3dstreaming.com/v5/demo/E3DSFeaturesTemplate/E3DS-Iframe-Demo.

{
    "core": {
        "domain": "connector.eagle3dstreaming.com",
        "userName": "demo",
        "appName": "E3DSFeaturesTemplate",
        "configurationName": "E3DS-Iframe-Demo"
    }
}

Now go to https://account.eagle3dstreaming.com/streaming-session-token-generator and follow the steps 1, 2, 3 and 4 sequentially as shown in the image.

Also you will need your username as mentioned in step 5.

In step 4 you will copy the token and paste it into the index.html page code as well as username. Final code for me looked like this:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico"/>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <meta name="theme-color" content="#000000"/>
    <meta name="description" content="Web site created using create-react-app"/>
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png"/>
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json"/>
    <title>React App</title>
    <script type="text/javascript" src="scripts/e3dsCore.min.js"></script>
    <script>
        window.onload = function () {
            const myToken = "18859020104138400193239781428531217018735238511822525/U2FsdGVkX18f3m0Z0NVkvkPGaqP583sPwXaBsx/7DZADOoZkM3M4CTI9+yHtyaLRnQxaKRBH/wPvi+EfpoUB3eYtZqM/A3o/PAGefi5zpvMUTqzb4nmXNWJOXR54JrrOSS69OdgXs1YirTcEiLVuKwKYOTIJS3YSHl62XtcSnN7F+8ZAvS/ULGusKgYT8uyQhttGhMYQjxVj1txV0A5sCtuZ+AncD99Tdcec4qbBPnhItm4ysqsJj3vA20tacNGiaq4owHEBkaWO7RSZMgN5xVoF4+7i+0b63m1OgNt7HVmUoF9NgRAGECRE9U8V48QXYamxNFfx8zuhqkKp+KwgBA=="
            const myUserName = "demo"
            e3ds_controller.main(myToken, myUserName);
        }
    </script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>

Now I get this error:

This is because, for rendering our video stream, we need a video-type element that will be displayed on the webpage. To add that, we need to include the following div with the structure exactly as given, with respected IDs and styles, inside our React App. For that we can change the functional component in App.tsx as such:

function App() {
    return (
            <div id="playerUI" style={{display: 'block'}}>
                <div id="player" style={{display: 'block'}}>
                    <video id="streamingVideo">
                        <source src="" type="video/mp4"/>
                    </video>
                </div>
            </div>
    )
}

Stream will start on the left side.

It might take some time to load, especially on the first load after a recent update and due to many other factors. That's why we need to show a progress bar and other elements to keep the user entertained during the process of loading the stream.

The whole source code can be found in the branch:
GitHub - e3ds/react-static-file-server as demo-static-token

Method 2: Generating a token at html fetch from server

Generating a token every time could be a problematic process. So, I have provided a Node.js app that uses our token API, and it can be found in this branch:
GitHub - e3ds/react-static-file-server at main

This is a combined app. First part contains the built version of the react app. Second part contains a rudimentary express.js app. This method only works with a prod build of the react app since it uses the express.js app to serve the file. So, react watch or live reload mode doesn’t work.

1. Checkout the branch
2. Open public/server.js
3. You have to replace these info in this image, Or you can try with these for now:

image-20240109-111300.png

4. you can collect API key from this URL: https://account.eagle3dstreaming.com/api-keys-management

5. Run setup.bat
6. Run build.bat
7. Then run token-server.bat
7. Open browser and go to: http://localhost:3000/

If all info was provided correctly, the session will start automatically.

How it works:

When a browser tries to fetch the index.html, the server queries the token from e3ds server and injects into the html along with clientUserName and serves it to the browser.

 Useful global functions

Here is a list of useful global functions. These functions will be called from the core library if they are defined in global scope. Inside functions required operation can be done for the functionality of the web app.

e3ds_controller.callbacks.onDataChannelOpen = function () {
    console.log("ob-onDataChannelOpen");
}

e3ds_controller.callbacks.onDataChannelClose = function () {
    console.log("ob-onDataChannelClose");
}

e3ds_controller.callbacks.onConfigAcquire = function () {
    console.log("ob-onConfigAcquire");
}

e3ds_controller.callbacks.onSessionExpired = function () {
    self.location = "assets/pages/session-expired.htm";
}

e3ds_controller.callbacks.onResponseFromUnreal = function (descriptor) {
    console.log("ob-onResponseFromUnreal");
    console.log("UnrealResponse: " + descriptor);
    document.getElementById('LatencyStats').innerHTML = descriptor;
}

e3ds_controller.callbacks.onReceivingAppAcquiringProgress = function (percent) {
    console.log("onReceivingAppAcquiringProgress: " + percent);
}


e3ds_controller.callbacks.onReceivingAppPreparationProgress = function (percent) {
    console.log("onReceivingAppPreparationProgress: " + percent);
}

e3ds_controller.callbacks.onReceivingAppStartingProgress = function (percent) {
    console.log("onReceivingAppStartingProgress: " + percent);
}

e3ds_controller.callbacks.onHtmlBind = function () {
    console.log("ob-onHtmlBind");
}


Explanations:
onConfigAcquire : called when configuration data arrives
onDataChannelOpen: called then communication channel between the browser and UE app is established
onDataChannelClose: called then communication channel between the browser and UE app is broken
onSessionExpired: called when stream session time expires
onHtmlBind: when system finish binding function to existed stick Ui elements


 Communication between web app and UE app

To send message to UE app from the web app call “e3ds_controller.sendToUnreal” .
we will do some major change into it soon. right now it expects a json object. we are planning to change it to a string
Example:

    window?.e3ds_controller.sendToUnreal({
      Teleport: pos
    });


When a message comes from the UE app the “onResponseFromUnreal(descriptor)“ function is called in global scope. The parameter of the function holds the message.

  • No labels