Flow Layout in an iFrame

React web application to demonstrate a simple video meeting experience embedded in an iframe.

Generic flow layout of participants in an iframe.Generic flow layout of participants in an iframe.

Generic flow layout of participants in an iframe.

Overview

This project demonstrates what a simple video meeting experience is like when embedded in an iframe of a web application.

Features Tech Stack
  • Voice and video conferencing
  • Audio and video with start and stop
  • Audio and video device selection
  • Sharable link with embedded conference id
  • HTML / CSS
  • JavaScript / ReactJS

Getting Started

Clone the Repository

Run the following:

git clone https://github.com/dolbyio-samples/meet-dolbyio-generic.git
cd meet-dolbyio-generic

Follow setup instructions

You'll need to complete a few setup steps as described in the README.

✓ Set your Dolby.io Consumer Key and Consumer Secret in voxeetUtils.js

Key Concepts

URL-Based Conference ID

To create a unique and personal conference experience, a cell ID is passed to the app in a URL parameter that looks like this: ?cell=8828308289fffff

While this unique identifier corresponds to a map location on our demonstration app, it essentially used to create a unique conference alias.

In this first code example from App.js: We can see how the URLSearchParams are used to return the Cell value, and then this value is used within React's useEffect lifecycle hook to call the method createConference(cell)

Through the use of promises within that hook, we call Dolby.io Communications APIs that are referenced from ./Utils/voxeetUtils.js - which after initialization, conveniently calls the chain of methods; createConference, joinConference, startVideo and sets the final state setIsLoaded for the UI to update.

// The ID of the map cell we are in.
const params = new URLSearchParams(window.location.search);
const cell = params.get('cell') || 'test123456789';

// These are the only characters that vary at this zoom level.
const locationIdForPresentation = cell.substring(5, 10);

function App() {
  const [isLoaded, setIsLoaded] = useState(false);
  useEffect(() => {
    if (cell) {
      createConference(cell).then((conf) => {
        joinConference(conf).then((conf) => {
          startVideo(conf).then((conf) => {
            setIsLoaded(true); // start the video as soon as you join the conference
          });
        });
      });
    }
  }, []);

  return (
    <div className="App">
      <div className="container">
        <div className="top">
          <div className="location-id">
            Location No. {locationIdForPresentation}
          </div>
          <div className="location-time">
            <LocationTime />
          </div>
        </div>
        <ParticipantGrid isLoaded={isLoaded} />
        <div className="bottom">
          <AppControls />
          <CallToActionButton />
          <div className="counterweight" />
        </div>
      </div>
    </div>
  );

Core Conference Functionality

Since we've put the main functions that call the Dolby.io Communications APIs in ./Utils/voxeetUtils.js you can easily reference the helper methods that call the Dolby.io Communications APIs.

Briefly, as we previously noted; When this code is instantiated from the app.js Script, we first initialize the SDK as seen on line 13. This script./Utils/voxeetUtils.js provides several helper methods to manage conference creation, manage joining and leaving, selecting sources, starting and stopping audio and video:

  • createConference
  • joinConference
  • leaveConference
  • startVideo
  • stopVideo
  • startAudio
  • stopAudio
  • getAudioDevices
  • changeAudioDevice
  • changeVideoDevice
import {
  initialize,
  session,
  conference,
  mediaDevice,
} from '@voxeet/voxeet-web-sdk';

// Enter your credentials from Dolby.io here:
// https://dolby.io/dashboard/applications/summary
const consumerKey = '<DOLBYIO_COMMUNICATIONS_API>';
const consumerSecret = '<DOLBYIO_COMMUNICATIONS_SECRET>';

initialize(consumerKey, consumerSecret);

/**
 * This function either creates a new session if there isn't anyone in one with that alias
 * or finds the conference if there already is.
 * It returns an object that can be passed into joinConference below();
 * @param {*} alias
 * @returns conference
 */
const createConference = (alias) => {
  return new Promise((resolve, reject) => {
    conference
      .create({ alias })
      .then((cellConference) => {
        resolve(cellConference);
      })
      .catch((err) => {
        console.error(err);
        reject(err);
      });
  });
};

// conference in/out
const joinConference = (conf) => {
  return new Promise((resolve, reject) => {
    conference
      .join(conf, {})
      .then((conf) => {
        resolve(conf);
      })
      .catch((err) => {
        console.error(err);
        reject(err);
      });
  });
};

const leaveConference = () => {
  conference.leave();
};

// video
const startVideo = () => {
  return new Promise((resolve, reject) => {
    conference
      .startVideo(session.participant)
      .then((res) => {
        resolve(res);
      })
      .catch((err) => {
        console.error(err);
      });
  });
};

const stopVideo = () => {
  conference
    .stopVideo(session.participant)
    .then(() => {})
    .catch((err) => {
      console.error(err);
    });
};

// audio
const startAudio = () => {
  conference
    .startAudio(session.participant)
    .then(() => {})
    .catch((err) => {
      console.error(err);
    });
};

const stopAudio = () => {
  conference
    .stopAudio(session.participant)
    .then(() => {})
    .catch((err) => {
      console.error(err);
    });
};

// media devices
const getAudioDevices = () => {
  return new Promise((resolve, reject) => {
    mediaDevice
      .enumerateAudioDevices()
      .then((value) => {
        resolve(value);
      })
      .catch((err) => {
        reject(err);
      });
  });
};

const getVideoDevices = () => {
  return new Promise((resolve, reject) => {
    mediaDevice
      .enumerateVideoDevices()
      .then((value) => {
        resolve(value);
      })
      .catch((err) => {
        reject(err);
      });
  });
};

const changeAudioDevice = (deviceId) => {
  mediaDevice
    .selectAudioInput(deviceId)
    .then(() => {})
    .catch((err) => console.error);
};

const changeVideoDevice = (deviceId) => {
  mediaDevice
    .selectVideoInput(deviceId)
    .then(() => {})
    .catch((err) => console.error);
};

export {
  createConference,
  joinConference,
  leaveConference,
  startVideo,
  stopVideo,
  startAudio,
  stopAudio,
  getAudioDevices,
  getVideoDevices,
  changeAudioDevice,
  changeVideoDevice,
};

Demo

This project was created to provide a generic meeting for any location around the world. By selecting a location on the map navigator application the popup opens providing an opportunity to conference with others about that place in the world. Some locations are "easter eggs" providing a more immersive video conferencing experience.

To try out the experience for yourself, visit the generic location demo and invite a friend to join you at that same location.

❗️

Event Code

You'll need an invitation code to access this demo website. Please contact [email protected] to obtain instructions on how to access this site.

Screenshot of a running session.Screenshot of a running session.

Screenshot of a running session.


Did this page help you?