Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / Node.js

Wexstream - Video Conferencing Platform with Node.js, React and Jitsi

4.93/5 (9 votes)
15 Jul 2023MIT14 min read 44.3K   389  
Video Conferencing Platform with Node.js, React and Jitsi
In this article, you will learn about Wexstream, a Video Conferencing Platform built with Node.js, React and Jitsi.

Image 1

Table of Contents

  1. Introduction
  2. Prerequisites
  3. Quick Overview
  4. Installing
  5. Run from Source
  6. Using the Code
    1. API
    2. Frontend
  7. Terms of Service
  8. History

Introduction

Wexstream is an open source video conferencing platform built with Node.js, React and Jitsi.

Wexstream lets you create a network and share your private video conferences with your network or create public video conferences and share them with people outside your network.

Wexstream lets you stay in touch with all your teams, family, friends, or colleagues. Instant video conferences, efficiently adapting to your scale for free.

  • Unlimited users: There are no artificial restrictions on the number of users or conference participants. Server power and bandwidth are the only limiting factors.
  • Privacy settings, passwords and meeting locks put the control in your hands.
  • Lock-protected rooms: Control the access to your conferences with a password.
  • Desktop screen sharing, chat, and many useful features.
  • Encrypted by default.
  • Protected conferences using TLS encryption and end-to-server/transit encryption.
  • High quality: Audio and video are delivered with the clarity and richness of Opus and VP8.
  • Web ready: No downloads are required of your friends to join the conversation. Wexstream works directly within their browsers as well. Simply share your conference URL with others to get started.
  • Mobile ready: Accessible, legible, and usable across all devices.
  • Users' personal data is neither resold nor communicated to third parties.
  • Users have the right to access, modify, rectify and delete their personal data.

Easy to Use

Wexstream is simple, flexible and easy to use, no matter your location.

Users can instantly jump into a webcast online, no download required.

Once registered, the user can benefit from the following services:

  • Easy networking between platform members
  • Provision of video conferencing tools
  • Provision of communication tools between platform members

The platform works as follows:

  1. The user creates a network by connecting with others.
  2. The user broadcasts private or public conferences.
  3. When broadcasting a conference, the user gets a URL that he can share to invite others to join him.
  4. When broadcasting a conference, the user's network is notified.

Secure

Wexstream protects your live and hosted content using TLS encryption and end-to-server/transit encryption. Plus, added privacy settings passwords and meeting locks puts the control in your hands.

Wexstream is committed to using all means to ensure the security and privacy of users' personal data.

Users' personal data is neither resold nor communicated to third parties.

The user has the right to access, modify, rectify and delete his personal data.

Neat Content

The user is expressly forbidden to publish any content, engage in any activity, stream any feed or create any account that is offensive, pornographic, violent, abusive, defamatory, threatening or obscene, illegal or intended to promote or commit an illegal act, including violations of intellectual property rights, privacy rights or proprietary rights, denigrating, slanderous, racist, xenophobic, contrary to morality and good morals, infringing content, undermining public order or rights, likely to infringe the rights, reputation and image of the platform and more generally, the content of which would violate the law and/or regulations, in particular of a criminal nature, includes his password, or purposely includes someone else's password, personal data, or is intended to solicit such data, misleads or deceives, or is likely to mislead or deceive, others as to his identity or affiliation with another person or organisation, breaches any of his obligations under the terms of use of the platform or any of its incorporated policies.

Prerequisites

  • Node.js
  • Express
  • MongoDB
  • React
  • MUI
  • JavaScript
  • Git

Quick Overview

In this section, you'll see a quick overview of the main pages.

Below is the login page:

Image 2

The user can authenticate through Google, Facebook or email by creating an account from the sign up page:

Image 3

Below is the about page:

Image 4

Below is the terms of service page:

Image 5

Below is the contact page:

Image 6

When the user signs in, he arrives to the home page where he can see his timeline:

Image 7

The timeline contains the video conferences of the user's network.

Below is the network page:

Image 8

From the network page, the user can search for users and send connection requests or private messages.

Below is the connections page:

Image 9

The connections page contains the user's network.

Below is the messages page:

Image 10

From the messages page, the user can read and manage his messages or send new messages.

Below is the notifications page:

Image 11

From the notifications page, the user can read and manage his notifications.

Below is the profile page:

Image 12

From the profile page, the user can see the private and public video conferences of a member of his network or public video conferences of a user outside his network.

Below is the settings page:

Image 13

From the settings page, the user can manage his settings or delete his account.

Below is the reset password page:

Image 14

From this page, the user who signed up with his email can change his password.

Below is the dialog for creating a new video conference:

Image 15

The user inputs a required title, an optional description and a flag that indicates whether the video conference is private or public. If the video conference is private, it will be available to its network only. Otherwise if the video conference is public, it will be available to everyone.

Below is the conference page:

Image 16

The user will obtain a unique video conference URL that he can share with his network if the conference is private or everyone if the conference is public. The user can start/stop his camera, share his screen with the participants, protect his conference with a password, raise/lower his hand, see the participants, send private messages to the participants and so on.

Installing

You can find installation instructions here.

Run from Source

Below are the instructions to run Wexstream from source code.

Prerequisites

Instructions

  1. Clone Wexstream repo:
    git clone https://github.com/aelassas/wexstream.git 
  2. Add api/.env file:
    NODE_ENV = development
    WS_PORT = 4003
    WS_HTTPS = false
    WS_PRIVATE_KEY = /etc/jitsi/meet/192.168.100.223.key
    WS_CERTIFICATE = /etc/jitsi/meet/192.168.100.223.crt
    WS_APP_HOST = localhost
    WS_DB_HOST = 127.0.0.1
    WS_DB_PORT = 27017
    WS_DB_SSL = false
    WS_DB_SSL_KEY = /etc/jitsi/meet/192.168.100.223.key
    WS_DB_SSL_CERT = /etc/jitsi/meet/192.168.100.223.crt
    WS_DB_SSL_CA = /etc/jitsi/meet/192.168.100.223.ca.pem
    WS_DB_DEBUG = false
    WS_DB_APP_NAME = wexstream
    WS_DB_AUTH_SOURCE = admin
    WS_DB_USERNAME = admin
    WS_DB_PASSWORD = PASSWORD
    WS_DB_NAME = wexstream
    WS_JWT_SECRET = JWT_SECRET
    WS_JWT_SUB = 192.168.100.223
    WS_JWT_EXPIRE_AT = 86400
    WS_TOKEN_EXPIRE_AT = 86400
    WS_SMTP_HOST = host
    WS_SMTP_PORT = 587
    WS_SMTP_USER = USER
    WS_SMTP_PASS = PASSWORD
    WS_SMTP_FROM = no-reply@wexstream.com
    WS_ADMIN_EMAIL = admin@wexstream.com
    WS_DEFAULT_LANGUAGE = en
    WS_CDN = /var/www/cdn/wexstream

    You must configure the following options:

    WS_DB_PASSWORD
    WS_JWT_SECRET 
    WS_JWT_SUB 
    WS_SMTP_HOST 
    WS_SMTP_PORT 
    WS_SMTP_USER 
    WS_SMTP_PASS 
    WS_SMTP_FROM
    WS_ADMIN_EMAIL 

    WS_JWT_SECRET must be the same as the JWT secret used in Jitsi.

    WS_JWT_SUB must be the FQDN or IP of the server where Jitsi is installed.

  3. Add frontend/.env file:
    REACT_APP_NODE_ENV = development
    REACT_APP_WS_DEFAULT_LANGUAGE = en
    REACT_APP_WS_DATE_FORMAT = llll
    REACT_APP_WS_PAGE_SIZE = 30
    REACT_APP_WS_JITSI_HOST = 192.168.100.223:444
    REACT_APP_WS_JITSI_API = https://192.168.100.223:444/external_api.js
    REACT_APP_WS_API_HOST = http://localhost:4003
    REACT_APP_WS_CDN = https://localhost/cdn/wexstream
    REACT_APP_WS_GOOGLE_CLIENT_ID = GOOGLE_CLIENT_ID
    REACT_APP_WS_FACEBOOK_APP_ID = FACEBOOK_APP_ID

    REACT_APP_WS_GOOGLE_CLIENT_ID is used for Google authentication.

    REACT_APP_WS_FACEBOOK_APP_ID is used for Facebook authentication.

    You must configure the following options:

    REACT_APP_WS_JITSI_HOST 
    REACT_APP_WS_JITSI_API
    REACT_APP_WS_GOOGLE_CLIENT_ID 
    REACT_APP_WS_FACEBOOK_APP_ID 
  4. Install nodemon:
    npm i -g nodemon
  5. Run api:
    cd ./api
    npm install
    npm run dev
  6. Run frontend:
    cd ./frontend
    npm install
    npm start
  7. Configure http://localhost/cdn
    • On Windows, install IIS and create C:\inetpub\wwwroot\cdn\wexstream folder.
    • On Linux, install NGINX and add cdn folder by changing /etc/nginx/sites-available/default as follows:
    server {
        listen 80 default_server;
        server_name _;
        
        ...
    
        location /cdn {
          alias /var/www/cdn;
        }
    }

    Create /var/www/cdn/wexstream folder and add the necessary permissions:

    mkdir /var/www/cdn/wexstream
    sudo chown -R $USER:$USER /var/www/cdn/wexstream

Using the Code

This section describes the software architecture of Wexstream including the database, the API and the frontend.

API

Wexstream API exposes all Wexstream functions needed for the frontend. The API follows the MVC design pattern. JWT is used for authentication. There are some functions that need authentication such as functions related to managing conferences and connections and others that do not need authentication such as signing up.

Image 17

  • ./api/models/ folder contains MongoDB models.
  • ./api/routes/ folder contains Express routes.
  • ./api/controllers/ folder contains controllers.
  • ./api/middlewares/ folder contains middlewares.
  • ./api/server.js is the main server where database connection is established and routes are loaded.
  • ./api/app.js is the main entry point of Wexstream API.

app.js

app.js is the main entry point of Wexstream API:

JavaScript
import app from './server.js'
import fs from 'fs'
import https from 'https'

const PORT = parseInt(process.env.WS_PORT) || 4000
const HTTPS = process.env.WS_HTTPS.toLocaleLowerCase() === 'true'
const PRIVATE_KEY = process.env.WS_PRIVATE_KEY
const CERTIFICATE = process.env.WS_CERTIFICATE

if (HTTPS) {
    https.globalAgent.maxSockets = Infinity
    const privateKey = fs.readFileSync(PRIVATE_KEY, 'utf8')
    const certificate = fs.readFileSync(CERTIFICATE, 'utf8')
    const credentials = { key: privateKey, cert: certificate }
    const httpsServer = https.createServer(credentials, app)

    httpsServer.listen(PORT, () => {
        console.log('HTTPS server is running on Port:', PORT)
    })
} else {
    app.listen(PORT, () => {
        console.log('HTTPS server is running on Port:', PORT)
    })
}

In app.js, we retrieve HTTPS setting variable which indicate whether https is enabled or not. If https is enabled, we create an https server using the provided private key and certificate and start listening. Otherwise, an http server is created and we start listening. app is the main server where database connection is established and routes are loaded.

server.js

server.js is in the main server:

JavaScript
import express from 'express'
import cors from 'cors'
import mongoose from 'mongoose'
import compression from 'compression'
import helmet from 'helmet'
import nocache from 'nocache'
import strings from './config/app.config.js'
import userRoutes from './routes/userRoutes.js'
import connectionRoutes from './routes/connectionRoutes.js'
import notificationRoutes from './routes/notificationRoutes.js'
import messageRoutes from './routes/messageRoutes.js'
import conferenceRoutes from './routes/conferenceRoutes.js'
import timelineRoutes from './routes/timelineRoutes.js'

const DB_HOST = process.env.WS_DB_HOST
const DB_PORT = process.env.WS_DB_PORT
const DB_SSL = process.env.WS_DB_SSL.toLowerCase() === 'true'
const DB_SSL_KEY = process.env.WS_DB_SSL_KEY
const DB_SSL_CERT = process.env.WS_DB_SSL_CERT
const DB_SSL_CA = process.env.WS_DB_SSL_CA
const DB_DEBUG = process.env.WS_DB_DEBUG.toLowerCase() === 'true'
const DB_AUTH_SOURCE = process.env.WS_DB_AUTH_SOURCE
const DB_USERNAME = process.env.WS_DB_USERNAME
const DB_PASSWORD = process.env.WS_DB_PASSWORD
const DB_APP_NAME = process.env.WS_DB_APP_NAME
const DB_NAME = process.env.WS_DB_NAME
const DB_URI = `mongodb://${encodeURIComponent(DB_USERNAME)}:${encodeURIComponent
                        (DB_PASSWORD)}@${DB_HOST}:${DB_PORT}/${DB_NAME}?
                         authSource=${DB_AUTH_SOURCE}&appName=${DB_APP_NAME}`

let options = {}
if (DB_SSL) {
    options = {
        ssl: true,
        sslValidate: true,
        sslKey: DB_SSL_KEY,
        sslCert: DB_SSL_CERT,
        sslCA: [DB_SSL_CA]
    }
}

mongoose.set('debug', DB_DEBUG)
mongoose.Promise = global.Promise
mongoose.connect(DB_URI, options)
    .then(
        () => { console.log('Database is connected') },
        err => { console.error('Cannot connect to the database:', err) }
    )

const app = express()
app.use(helmet.contentSecurityPolicy())
app.use(helmet.dnsPrefetchControl())
app.use(helmet.crossOriginEmbedderPolicy())
app.use(helmet.frameguard())
app.use(helmet.hidePoweredBy())
app.use(helmet.hsts())
app.use(helmet.ieNoOpen())
app.use(helmet.noSniff())
app.use(helmet.permittedCrossDomainPolicies())
app.use(helmet.referrerPolicy())
app.use(helmet.xssFilter())
app.use(helmet.originAgentCluster())
app.use(helmet.crossOriginResourcePolicy({ policy: 'cross-origin' }))
app.use(helmet.crossOriginOpenerPolicy())
app.use(nocache())
app.use(compression({ threshold: 0 }))
app.use(express.urlencoded({ limit: '50mb', extended: true }))
app.use(express.json({ limit: '50mb' }))
app.use(cors())
app.use('/', userRoutes)
app.use('/', connectionRoutes)
app.use('/', notificationRoutes)
app.use('/', messageRoutes)
app.use('/', conferenceRoutes)
app.use('/', timelineRoutes)

strings.setLanguage(process.env.WS_DEFAULT_LANGUAGE)

export default app

First of all, we build MongoDB connection string, then we establish a connection with Wexstream MongoDB database. Then we create an Express app and load middlewares. Finally, we load Express routes and export app.

Routes

There are six routes in Wexstream API. Each route has its own controller following the MVC design pattern and SOLID principles. Below are the main routes:

  • userRoutes: Provides REST functions related to users
  • connectionRoutes: Provides REST functions related to connections between users
  • conferenceRoutes: Provides REST functions related to conferences
  • timelineRoutes: Provides REST functions related to timelines
  • messageRoutes: Provides REST functions related to messages
  • notificationRoutes: Provides REST functions related to notifications

We are not going to explain each route one by one. We'll take, for example, conferenceRoutes and see how it was made:

JavaScript
import express from 'express'
import routeNames from '../config/conferenceRoutes.config.js'
import authJwt from '../middlewares/authJwt.js'
import * as conferenceController from '../controllers/conferenceController.js'

const routes = express.Router()

routes.route(routeNames.create).post(authJwt.verifyToken, conferenceController.create)
routes.route(routeNames.update).post(authJwt.verifyToken, conferenceController.update)
routes.route(routeNames.addMember).post(authJwt.verifyToken, 
                                        conferenceController.addMember)
routes.route(routeNames.removeMember).post(authJwt.verifyToken, 
                                           conferenceController.removeMember)
routes.route(routeNames.delete).delete(authJwt.verifyToken, 
                                       conferenceController.deleteConference)
routes.route(routeNames.getConference).get(authJwt.verifyToken, 
                                           conferenceController.getConference)
routes.route(routeNames.getConferences).get(authJwt.verifyToken, 
                                            conferenceController.getConferences)
routes.route(routeNames.getMembers).get(authJwt.verifyToken, 
                                        conferenceController.getMembers)
routes.route(routeNames.close).post(authJwt.verifyToken, conferenceController.close)

export default routes

First of all, we create an Express Router. Then, we create routes using its name, its method, middlewares and its controller.

routeNames contains conferenceRoutes route names:

JavaScript
export default {
    create: '/api/create-conference',
    update: '/api/update-conference/:conferenceId',
    addMember: '/api/add-member/:conferenceId/:userId',
    removeMember: '/api/remove-member/:conferenceId/:userId',
    delete: '/api/delete-conference/:conferenceId',
    getConference: '/api/get-conference/:conferenceId',
    getConferences: '/api/get-conferences/:userId/:isPrivate/:page/:pageSize',
    getMembers:  '/api/get-members/:conferenceId',
    close:  '/api/close-conference/:userId/:conferenceId'
}

conferenceController contains the main business logic regarding conferences. We are not going to see all the source code of the controller since it's quite large but we'll take create and getConferences controller functions for example.

Below is Conference model:

JavaScript
import mongoose from 'mongoose'

const Schema = mongoose.Schema

const conferenceSchema = new Schema({
    title: {
        type: String,
        required: [true, "can't be blank"],
        index: true
    },
    description: {
        type: String,
        index: true
    },
    isPrivate: {
        type: Boolean,
        default: true
    },
    isLive: {
        type: Boolean,
        default: false
    },
    speaker: {
        type: Schema.Types.ObjectId,
        required: true,
        ref: 'User'
    },
    members: [{
        type: Schema.Types.ObjectId,
        ref: 'User'
    }],
    broadcastedAt: {
        type: Date
    },
    finishedAt: {
        type: Date
    },
}, {
    timestamps: true,
    strict: true,
    collection: 'Conference'
})

const conferenceModel = mongoose.model('Conference', conferenceSchema)

conferenceModel.on('index', (err) => {
    if (err) {
        console.error('Conference index error: %s', err)
    } else {
        console.info('Conference indexing complete')
    }
})

export default conferenceModel

A conference is composed of a title, an optional description, isPrivate and isLive flags, a speaker, members, broadcast and finish date times.

Below is create controller function:

JavaScript
export const create = (req, res) => {
    const conference = new Conference(req.body)
    conference.save()
        .then(conf => {
            res.status(200).json(conf)
        })
        .catch(err => {
            console.error(strings.DB_ERROR, err)
            res.status(400).send(strings.DB_ERROR + err)
        })
}

In this function, we retrieve the body of the request and we create the conference.

Below is getConferences controller function:

JavaScript
export const getConferences = (req, res) => {
    const page = parseInt(req.params.page)
    const pageSize = parseInt(req.params.pageSize)
    let query = { speaker: req.params.userId }

    if (req.params.isPrivate === 'false') {
        query.isPrivate = false
    }

    Conference.find(query, null, { skip: ((page - 1) * pageSize), limit: pageSize })
        .sort({ createdAt: -1 })
        .then(confs => {
            res.json(confs)
        })
        .catch(err => {
            console.error(strings.DB_ERROR, err)
            res.status(400).send(strings.DB_ERROR + err)
        })
}

In this controller function, we retrieve the conferences depending on the page, pageSize, userId and isPrivate flag.

Frontend

The frontend is a web application built with Node.js, React and MUI.

Image 18

  • ./frontend/assets/ folder contains CSS files.
  • ./frontend/pages/ folder contains React pages.
  • ./frontend/components/ folder contains React components.
  • ./frontend/services/ contains Wexstream API client services.
  • ./frontend/App.js is the main React App that contains routes.
  • ./frontend/index.js is the main entry point of the frontend.

App.js is the main react App:

JavaScript
import React, { lazy, Suspense } from 'react'
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'

const SignIn = lazy(() => import('./pages/SignIn'))
const SignUp = lazy(() => import('./pages/SignUp'))
const Home = lazy(() => import('./pages/Home'))
const Conference = lazy(() => import('./pages/Conference'))
const Profile = lazy(() => import('./pages/Profile'))
const Search = lazy(() => import('./pages/Search'))
const Notifications = lazy(() => import('./pages/Notifications'))
const Connections = lazy(() => import('./pages/Connections'))
const ToS = lazy(() => import('./pages/ToS'))
const About = lazy(() => import('./pages/About'))
const Messages = lazy(() => import('./pages/Messages'))
const Settings = lazy(() => import('./pages/Settings'))
const ResetPassword = lazy(() => import('./pages/ResetPassword'))
const Contact = lazy(() => import('./pages/Contact'))
const NoMatch = lazy(() => import('./pages/NoMatch'))

const App = () => (
    <Router>
        <div className="App">
            <Suspense fallback={<></>}>
                <Routes>
                    <Route exact path="/sign-in" element={<SignIn />} />
                    <Route exact path="/sign-up" element={<SignUp />} />
                    <Route exact path="/" element={<Home />} />
                    <Route exact path="/home" element={<Home />} />
                    <Route exact path="/conference" element={<Conference />} />
                    <Route exact path="/profile" element={<Profile />} />
                    <Route exact path="/search" element={<Search />} />
                    <Route exact path="/notifications" element={<Notifications />} />
                    <Route exact path="/connections" element={<Connections />} />
                    <Route exact path="/messages" element={<Messages />} />
                    <Route exact path="/settings" element={<Settings />} />
                    <Route exact path="/reset-password" element={<ResetPassword />} />
                    <Route exact path="/tos" element={<ToS />} />
                    <Route exact path="/about" element={<About />} />
                    <Route exact path="/contact" element={<Contact />} />

                    <Route path="*" element={<NoMatch />} />
                </Routes>
            </Suspense>
        </div>
    </Router>
)

export default App

We are using React lazy loading to load each route.

Below is the main function for starting a conference in Conference page:

JavaScript
import { JITSI_API, JITSI_HOST, isMobile } from '../config/env'

const startConf = () => {
    setConference(conference)

    const script = document.createElement('script')
    script.src = JITSI_API
    script.id = 'external-api'
    script.setAttribute('defer', 'defer')
    document.body.appendChild(script)

    // External API is loaded
    const externalApi = document.getElementById('external-api')

    externalApi.addEventListener('load', () => {
        if (window.JitsiMeetExternalAPI) {
            if (!conference.isLive && (conference.speaker._id === user._id)) {
                updateConf(conference, 
                { isLive: true, broadcastedAt: Date.now() }, () => {
                    setConferenceUrl(window.location.href)
                    setStartConf(true)
                })
            } else {
                setConferenceUrl(window.location.href)
                setStartConf(true)
            }
        } else {
            setLoading(false)
            setExternalApiError(true)
        }
    })

In this function, we load Jitsi external API.

Jitsi is a set of open source projects which empower users to use and deploy video conferencing platforms with state-of-the-art video quality and features.

We then start the conference through the following function:

JavaScript
import React, { useCallback, useEffect, useState } from 'react'
import { JITSI_API, JITSI_HOST, isMobile } from '../config/env'

let domain = JITSI_HOST
let api = {}

const startConference = useCallback(() => {
    localStorage.removeItem('jitsiLocalStorage')
    localStorage.setItem('jitsiLocalStorage', 
                          JSON.stringify({ language: user.language }))

    const options = {
        roomName: conference._id,
        width: '100%',
        height: '100%',
        configOverwrite: {
            prejoinPageEnabled: false,
            useHostPageLocalStorage: true,
            disableDeepLinking: true,
            disabledNotifications: ['dialog.thankYou']
        },
        interfaceConfigOverwrite: {
            // overwrite interface properties
        },
        parentNode: document.querySelector('#conf'),
        userInfo: {
            displayName: user.fullName
        },
        lang: user.language,
        jwt: user.accessToken
    }
    api = new window.JitsiMeetExternalAPI(domain, options)

    api.addEventListeners({
        readyToClose: handleClose,
        videoConferenceJoined: handleVideoConferenceJoined,
        videoConferenceLeft: handleVideoConferenceLeft,
        participantLeft: handleParticipantLeft,
        participantJoined: handleParticipantJoined,
        participantRoleChanged: handleParticipantRoleChanged,
        participantKickedOut: handleParticipantKickedOut,
        audioMuteStatusChanged: handleMuteStatus,
        videoMuteStatusChanged: handleVideoStatus
    })

    window.onbeforeunload = (e) => {
        localStorage.removeItem('jitsiLocalStorage')
        setExit(true)
    }

    if (conference.isLive && conference.speaker._id === user._id) {
        createTimelineEntries(user._id, conference._id, true)
    }
}, [user, conference])

In the function above, we create a new Jitsi API with the options and the event listeners, we start the conference, and create the timeline entries.

We are not going to cover each page of the frontend, but you can open the source code and see each one if you want to.

Terms of Service

Preamble

Wexstream lets you stay in touch with all your teams, family, friends, or colleagues. Instant video conferences, efficiently adapting to your scale for free.

Wexstream was developed using most recent and performant technologies, which allows the platform to handle a large number of conferences and participants.

  • Unlimited users: There are no artificial restrictions on the number of users or conference participants. Server power and bandwidth are the only limiting factors.
  • Privacy settings, passwords and meeting locks puts the control in your hands.
  • Lock-protected rooms: Control the access to your conferences with a password.
  • Desktop screen sharing, chat, and many useful features.
  • Encrypted by default.
  • Protected conferences using TLS encryption and end-to-server/transit encryption.
  • High quality: Audio and video are delivered with the clarity and richness of Opus and VP8.
  • Web ready: No downloads are required of your friends to join the conversation. Wexstream works directly within their browsers as well. Simply share your conference URL with others to get started.
  • Mobile ready: Accessible, legible, and usable across all devices.
  • Users' personal data is neither resold nor communicated to third parties.
  • Users have the right to access, modify, rectify and delete their personal data.

Subscribing

To access the services, the user must create an account by registering for free.

The user is required to provide true and accurate information which he undertakes to update immediately in the event of any changes.

Access to the platform is protected by a username and password chosen by the user when registering. The user is solely responsible for any use that may be made of his username and password, and sole guarantor of their confidentiality, as well as any use of his account.

In the event that the user provides false, inaccurate, outdated or incomplete data, Wexstream will be entitled to suspend or close his account and to refuse him, in the future, access to all or part of the services.

Services

Once registered, the user can benefit from the following services:

  • Easy networking between platform members
  • Provision of video conferencing tools
  • Provision of communication tools between platform members

The platform works as follows:

  1. The user creates a network by connecting with others.
  2. The user broadcasts private or public conferences.
  3. When broadcasting a conference, the user gets a URL that he can share to invite others to join him.
  4. When broadcasting a conference, the user's network is notified.

Access to Services

Access to the platform and the services is exclusively reserved for registered users. Users broadcast online learning videos, webinars, lectures, or live streams, or attend online learning courses, webinairs, conferences, or live streams, and have access to IT and telecommunication resources allowing access to the platform.

The platform is accessible 24/7 for all users. Wexstream reserves the right, without notice or compensation, to temporarily or permanently close the platform or access to one or more services to make any update, modifications or change in operational methods, servers and accessibility hours, without this list being exhaustive. Wexstream reserves the right to make any modifications and improvements to the platform and to the services that Wexstream finds necessary or useful for the proper functioning of the platform and its services.

Litigations

Wexstream is not responsible for the collaboration between the broadcasters and the users, but Wexstream may be able to help resolve any dispute.

Commitments

Users undertake to make fair use of the platform and services and expressly refrain from circumventing the services and the platform. Consequently, any user is prohibited from extracting content from the platform for a similar or concurrent activity.

Responsibility

The user is responsible for the direct or indirect damage that he is likely to suffer as a result of inaccurate, incomplete, and/or misleading information that he provides when registering or in the absence of updating his information, for which he alone assumes the consequences.

The user is responsible for all the content he chooses to broadcast.

The user is expressly forbidden to publish any content, engage in any activity, stream any feed or create any account that is offensive, pornographic, violent, abusive, defamatory, threatening or obscene, illegal or intended to promote or commit an illegal act, including violations of intellectual property rights, privacy rights or proprietary rights, denigrating, slanderous, racist, xenophobic, contrary to morality and good morals, infringing content, undermining public order or rights, likely to infringe the rights, reputation and image of the platform and more generally, the content of which would violate the law and/or regulations, in particular of a criminal nature, includes his password, or purposely includes someone else's password, personal data, or is intended to solicit such data, misleads or deceives, or is likely to mislead or deceive, others as to his identity or affiliation with another person or organisation, breaches any of his obligations under the terms of use of the platform or any of its incorporated policies.

Privacy

Wexstream protects your live and hosted content using TLS encryption and end-to-server/transit encryption. Plus, added privacy settings passwords and meeting locks puts the control in your hands.

Wexstream is committed to using all means to ensure the security and privacy of users' personal data.

Users' personal data is neither resold nor communicated to third parties.

The user has the right to access, modify, rectify and delete his personal data.

Duration, Termination and Sanctions

This contract is concluded for an indefinite period from the acceptance of the terms of use of the platform by the user.

If the user does not respect these terms of use and/or commits any breach of the laws and regulations in force, Wexstream is entitled to suspend or close the user's account, automatically, and to deny him, in the future, access to all or part of the services, without prejudice to any damages and interest that Wexstream will be entitled to claim.

Modifications of Terms of Service

Wexstream reserves the right to modify all or part of these conditions of use.

Wexstream will inform the user of the modifications made to these general conditions as soon as they are posted on the platform.

Applicable Law and Competent Jurisdiction

Any dispute relating to the formation of these terms of service, conclusion, interpretation and/or execution falls under the exclusive jurisdiction of the courts.

History

License

This article, along with any associated source code and files, is licensed under The MIT License