Skip to content

Instantly share code, notes, and snippets.

@dzeitman
Last active November 4, 2021 16:24
Show Gist options
  • Save dzeitman/b5cdcd04185d03705cf7d5c98ffa91f6 to your computer and use it in GitHub Desktop.
Save dzeitman/b5cdcd04185d03705cf7d5c98ffa91f6 to your computer and use it in GitHub Desktop.
Dolby.io-CascadiaJs Workshop - Fiddle Demo
/** Create a list of Cities for our Money Heist Characters */
const cities = ['Seattle', 'Vancouver', 'Portland', 'Tokyo', 'Berlin', 'Palermo', 'Nairobi', 'Denver', 'Helsinki', 'Rio', 'Moscow', 'Oslo'];
let randomName = cities[Math.floor(Math.random() * cities.length)];
// We'll pulls some images that have been named after cities... {Money Heist} and replace our city name in URL and add some cloudinary transformations.
let imagePlaceholder = `https://res.cloudinary.com/dolby-io/image/upload/e_art:red_rock/ar_1:1,c_fill,g_auto,r_max,w_50/v1634690310/dolby-hackathon/cities/${randomName}.png`
/** Update varibles when form input changes */
function updateNameValue(e) {
randomName = e.target.value;
}
// URL to our Token Server
const tokenServerURL = 'Enter the url to your token server here';
/** initializeToken authorization flow on script load **/
(function () {
try {
getTokenAndInitalize()
} catch (e) {
alert('Something went wrong initalizaton : ' + e);
}
})();
/** Fetch our token and start initialization of SDK, update UI sources */
async function getTokenAndInitalize() {
return fetch(tokenServerURL)
.then((res) => {
return res.json();
})
.then((result) => {
VoxeetSDK.initializeToken(result.access_token, refreshToken);
return result.access_token
})
.then((token) => {
console.info('token received', token);
initializeConferenceSession()
})
.catch((error) => {
console.error(error);
});
}
/** Refresh Token is called when token expiration is 50% completed, this keeps the app initialized */
async function refreshToken() {
return fetch(tokenServerURL)
.then((res) => {
return res.json();
})
.then((json) => json.access_token)
.catch((error) => {
console.error(error);
});
}
/** Create the participantInfo object and open the session with the object */
async function initializeConferenceSession() {
let participantInfo = { name: randomName, avatarUrl: imagePlaceholder, externalId: randomName }
try {
// Open a session for the user
await VoxeetSDK.session.open(participantInfo);
// Initialize the UI
initUI();
console.log('session initialized!');
} catch (e) {
alert('Something went wrong: ' + e);
}
}
/* Dolby.io Event handlers */
// When a stream is added to the conference
VoxeetSDK.conference.on('streamAdded', (participant, stream) => {
if (stream.type === 'ScreenShare') {
return addScreenShareNode(stream);
}
if (stream.getVideoTracks().length) {
// Only add the video node if there is a video track
addVideoNode(participant, stream);
}
addParticipantNode(participant);
});
// When a stream is updated
VoxeetSDK.conference.on('streamUpdated', (participant, stream) => {
if (stream.type === 'ScreenShare') return;
if (stream.getVideoTracks().length) {
// Only add the video node if there is a video track
addVideoNode(participant, stream);
} else {
removeVideoNode(participant);
}
});
// When a stream is removed from the conference
VoxeetSDK.conference.on('streamRemoved', (participant, stream) => {
if (stream.type === 'ScreenShare') {
return removeScreenShareNode();
}
removeVideoNode(participant);
removeParticipantNode(participant);
});
//module.js:
var configObject = () => {
return {
"customerKey": "ckOi1Ea7j39ItpKQTDWVCQ==",
"customerSecret": "kxp5VT6TuKqae5tubdXgmr5ARkqnZY6GPuD23u0Ilk0="
};
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Simple Web Video Conference Application</title>
<script type="text/javascript" src="https://unpkg.com/@voxeet/voxeet-web-sdk@latest/dist/voxeet-sdk.js">
</script>
<script type="text/javascript" src="ui.js"></script>
<meta http-equiv="Content-Security-Policy"
content="default-src * self blob: data: gap:; style-src * self 'unsafe-inline' blob: data: gap:; script-src * 'self' 'unsafe-eval' 'unsafe-inline' blob: data: gap:; object-src * 'self' blob: data: gap:; img-src * self 'unsafe-inline' blob: data: gap:; connect-src self * 'unsafe-inline' blob: data: gap:; frame-src * self blob: data: gap:;">
<!-- CSS only -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We" crossorigin="anonymous">
<!-- JavaScript Bundle with Popper -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/js/bootstrap.bundle.min.js"
integrity="sha384-U1DAWAznBHeqEIlVSCgzq+c9gqGAJn5c/t99JyeKa9xxaYpSvHU5awsuZVVFIhvj" crossorigin="anonymous">
</script>
<script src="https://kit.fontawesome.com/d8d772b4af.js" crossorigin="anonymous"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-icons/1.5.0/font/bootstrap-icons.min.css"
rel="stylesheet" crossorigin="anonymous">
<link href="./styles.css" rel="stylesheet">
</head>
<body style="background-color: white;">
<div id="video-container" class="videos-container">
</div>
<div id="clip-container" class="clip-container1"></div>
<div id="screenshare-container" class="screenshare-container"></div>
<div class="main-controls-container">
<div class="message-item">
<div class="mb-3">
<div for="alias-input" class="form-text">Conference alias:</div>
<input id="alias-input" value="dev-portal" class="form-control-lg" aria-describedby="aliasHelp" />
<div id="aliasHelp" class="form-text">Enter a unique conference name</div>
</div>
<div class="btn-group">
<button id="join-btn" class="btn btn-primary" disabled>Join</button>
<button id="leave-btn" class="btn btn-primary" disabled>Leave</button>
</div>
<div class="mb-3">
<div id="name-message" class="form-text">You are logged out.</div>
<div id="record-status" class="form-text" style="color: red;">Not Recording</div>
<div id="label-dolby-voice" class="form-text">Dolby Voice Off</div>
</div>
<div class="btn-group-sm">
<button type="button" class="btn btn-primary" id="start-video-btn" disabled> Start
Video</button>
<button type="button" class="btn btn-primary" id="stop-video-btn" disabled> Stop
Video</button>
<button type="button" class="btn btn-primary" id="start-audio-btn" disabled> Start
Audio</button>
<button type="button" class="btn btn-primary" id="stop-audio-btn" disabled> Stop
Audio</button>
</div>
<div class="btn-group-sm">
<button type="button" class="btn btn-warning" id="start-screenshare-btn" disabled> Start
Screenshare</button>
<button type="button" class="btn btn-warning" id="stop-screenshare-btn" disabled> Stop
Screenshare</button>
</div>
<div class="btn-group-sm">
<button type="button" class="btn btn-danger" id="start-recording-btn" disabled> Start
Recording</button>
<button type="button" class="btn btn-danger" id="stop-recording-btn" disabled> Stop
Recording</button>
</div>
<span id="clip-player-controls" style="visibility:hidden;">
<label for="clip-url-input" class="form-text">Enter a video URL</label>
<input id="clip-url-input"
value="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
class="form-control" aria-describedby="clipURLHelp" />
<div class="btn-group-sm p-3">
<button type="button" class="btn btn-success" id="start-clip-btn" disabled> Begin</button>
<button type="button" class="btn btn-success" id="play-clip-btn" disabled> Play </button>
<button type="button" class="btn btn-success" id="pause-clip-btn" disabled> Pause </button>
<button type="button" class="btn btn-success" id="stop-clip-btn" disabled> End</button>
</div>
</span>
<h3 class="form-text">Participants</h3>
<ul id="participants-list" class="list-group">
</ul>
</div>
</div>
<script type="text/javascript" src="client.js"></script>
<script type="text/javascript" src="video-controller.js"></script>
</body>
</html>
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron')
const path = require('path')
function createWindow() {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 1920,
height: 1080,
webPreferences: {
nodeIntegration: true,
preload: path.join(__dirname, 'preload.js'),
},
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
createWindow()
app.on('activate', function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
{
"name": "Watch Party v3",
"productName": "Watch Party v3",
"description": "My Electron application description",
"keywords": [],
"main": "./main.js",
"version": "1.0.0",
"author": "dzeit",
"scripts": {
"start": "electron ."
},
"dependencies": {},
"devDependencies": {
"electron": "13.1.7"
}
}
// All of the Node.js APIs are available in the preload process.
// It has the same sandbox as a Chrome extension.
window.addEventListener('DOMContentLoaded', () => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector)
if (element) element.innerText = text
}
for (const type of ['chrome', 'node', 'electron']) {
replaceText(`${type}-version`, process.versions[type])
}
})
// This file is required by the index.html file and will
// be executed in the renderer process for that window.
// No Node.js APIs are available in this process because
// `nodeIntegration` is turned off. Use `preload.js` to
// selectively enable features needed in the rendering
// process.
/* app Styles */
.flipped-video {
transform: rotateY(180deg);
-webkit-transform: rotateY(180deg); /* Safari and Chrome */
-moz-transform: rotateY(180deg); /* Firefox */
}
.videos-container {
display: flex;
flex-wrap: wrap;
flex-direction: row;
justify-content: flex-start;
align-items:flex-start;
position:absolute;
left:30px;
top: 30px;
bottom:30px;
right: 420px;
background-color: ghostwhite;
padding: 20px;
}
.screenshare-container {
display: flex;
flex-wrap: wrap;
justify-content: flex-end;
align-items:flex-end;
position:absolute;
left:30px;
top: 30px;
bottom:30px;
right: 420px;
}
.screenshare {
z-index: 25;
max-width: 60%;
max-height: 60%;
margin: 10px;
border: 3px solid #333;
background-color: ghostwhite;
}
.video-item {
max-width: 240px;
max-height: 240px;
/* width: 320px;
height: 240px; */
margin: 10px;
border: 2px solid #333;
box-shadow: 12px 12px 2px 1px rgba(152, 152, 154, 0.2);
}
.button-style {
border-radius: 1em;
margin: 0 0.3em 0.3em 0;
min-width: 80px;
}
.button-style-old {
display: inline-block;
padding: 0.3em 1.2em;
margin: 0 0.3em 0.3em 0;
border-radius: 2em;
box-sizing: border-box;
text-decoration: none;
font-family: 'Roboto', sans-serif;
font-weight: 300;
color: #FFFFFF;
background-color: #4eb5f1;
text-align: center;
transition: all 0.2s;
min-width: 150px;
}
.main-controls-container {
display: flex;
/* flex-wrap:wrap; */
flex-direction: column;
justify-content:right;
align-items:center;
position:absolute;
right:30px;
top: 30px;
width: 400px;
padding: 5px;
}
.list-item{
text-decoration: none;
}
.button-controls-container {
}
.message-item {
display: inline-block;
padding: 0.5em;
margin: 0.3em 0.3em 0.3em 0;
box-sizing: border-box;
text-decoration: none;
font-family: 'Roboto', sans-serif;
font-weight: 300;
color: #FFFFFF;
background-color: #b5c6d0;
text-align: center;
transition: all 0.2s;
width: 100%;
height: 100%;
border-radius: 1em;
}
.flexbox-item {
/* width: 200px; */
margin: 10px;
border: 1px solid #eee;
background-color: #dfdfdf;
}
.flexbox-item-1 {
width: 200px;
margin: 10px;
border: 1px solid #eee;
background-color: #dfdfdf;
min-height: 44px;
}
.controls {
width: 100%;
border: 1px solid #eee;
background-color: #dfdfdf;
}
html {
/* font-size: 10px;
background-color: #ffc600; */
}
body {
background: #eee;
font-family: 'helvetica neue';
font-weight: 200;
font-size: 20px;
}
p {
/* margin: 0 0 3rem; */
}
const initUI = () => {
const nameMessage = document.getElementById('name-message');
const conferenceAliasInput = document.getElementById('alias-input');
const joinButton = document.getElementById('join-btn');
const leaveButton = document.getElementById('leave-btn');
const lblDolbyVoice = document.getElementById('label-dolby-voice');
const startVideoBtn = document.getElementById('start-video-btn');
const stopVideoBtn = document.getElementById('stop-video-btn');
const startAudioBtn = document.getElementById('start-audio-btn');
const stopAudioBtn = document.getElementById('stop-audio-btn');
const startScreenShareBtn = document.getElementById('start-screenshare-btn');
const stopScreenShareBtn = document.getElementById('stop-screenshare-btn');
const startRecordingBtn = document.getElementById('start-recording-btn');
const stopRecordingBtn = document.getElementById('stop-recording-btn');
// Workshop Part three hide html elements / uncomment // showPlayer.style = ""; to show clip video controller
const showPlayer = document.getElementById('clip-player-controls');
showPlayer.style = "";
// Update the login message with the name of the user
nameMessage.innerHTML = `You are logged in as ${randomName}`;
// nameInput.value = randomName;
joinButton.disabled = false;
joinButton.onclick = () => {
// Default conference parameters
// See: https://docs.dolby.io/interactivity/docs/js-client-sdk-model-conferenceparameters
let conferenceParams = {
liveRecording: true,
rtcpMode: "average", // worst, average, max
ttl: 0,
videoCodec: "H264", // H264, VP8
dolbyVoice: true
};
// See: https://docs.dolby.io/interactivity/docs/js-client-sdk-model-conferenceoptions
let conferenceOptions = {
alias: conferenceAliasInput.value,
params: conferenceParams,
};
// 1. Create a conference room with an alias
VoxeetSDK.conference.create(conferenceOptions)
.then((conference) => {
// See: https://docs.dolby.io/interactivity/docs/js-client-sdk-model-joinoptions
const joinOptions = {
constraints: {
audio: false,
video: true
},
simulcast: false
};
// 2. Join the conference
VoxeetSDK.conference.join(conference, joinOptions)
.then((conf) => {
lblDolbyVoice.innerHTML = `Dolby Voice is ${conf.params.dolbyVoice ? 'On' : 'Off'}.`;
conferenceAliasInput.disabled = true;
joinButton.disabled = true;
leaveButton.disabled = false;
startVideoBtn.disabled = true;
stopVideoBtn.disabled = false;
startAudioBtn.disabled = false;
stopAudioBtn.disabled = true;
startScreenShareBtn.disabled = false;
startRecordingBtn.disabled = false;
startClipBtn.disabled = false;
playClipBtn.disabled = true;
pauseClipBtn.disabled = true;
stopClipBtn.disabled = true;
})
.catch((e) => console.log(e));
})
.catch((e) => console.log(e));
};
leaveButton.onclick = () => {
// Leave the conference
VoxeetSDK.conference.leave()
.then(() => {
lblDolbyVoice.innerHTML = '';
conferenceAliasInput.disabled = false;
joinButton.disabled = false;
leaveButton.disabled = true;
startVideoBtn.disabled = true;
stopVideoBtn.disabled = true;
startAudioBtn.disabled = true;
stopAudioBtn.disabled = true;
startScreenShareBtn.disabled = true;
stopScreenShareBtn.disabled = true;
startRecordingBtn.disabled = true;
stopRecordingBtn.disabled = true;
startClipBtn.disabled = true;
playClipBtn.disabled = true;
pauseClipBtn.disabled = true;
stopClipBtn.disabled = true;
})
.catch((e) => console.log(e));
};
startVideoBtn.onclick = () => {
// Start sharing the video with the other participants
VoxeetSDK.conference.startVideo(VoxeetSDK.session.participant)
.then(() => {
startVideoBtn.disabled = true;
stopVideoBtn.disabled = false;
})
.catch((e) => console.log(e));
};
stopVideoBtn.onclick = () => {
// Stop sharing the video with the other participants
VoxeetSDK.conference.stopVideo(VoxeetSDK.session.participant)
.then(() => {
stopVideoBtn.disabled = true;
startVideoBtn.disabled = false;
})
.catch((e) => console.log(e));
};
startAudioBtn.onclick = () => {
// Start sharing the Audio with the other participants
VoxeetSDK.conference.startAudio(VoxeetSDK.session.participant)
.then(() => {
startAudioBtn.disabled = true;
stopAudioBtn.disabled = false;
})
.catch((e) => console.log(e));
};
stopAudioBtn.onclick = () => {
// Stop sharing the Audio with the other participants
VoxeetSDK.conference.stopAudio(VoxeetSDK.session.participant)
.then(() => {
stopAudioBtn.disabled = true;
startAudioBtn.disabled = false;
})
.catch((e) => console.log(e));
};
startScreenShareBtn.onclick = () => {
// Start the Screen Sharing with the other participants
VoxeetSDK.conference.startScreenShare()
.then(() => {
startScreenShareBtn.disabled = true;
stopScreenShareBtn.disabled = false;
})
.catch((e) => console.log(e));
};
stopScreenShareBtn.onclick = () => {
// Stop the Screen Sharing
VoxeetSDK.conference.stopScreenShare()
.catch((e) => console.log(e));
};
startRecordingBtn.onclick = () => {
let recordStatus = document.getElementById('record-status');
// Start recording the conference
VoxeetSDK.recording.start()
.then(() => {
recordStatus.innerText = 'Recording...';
startRecordingBtn.disabled = true;
stopRecordingBtn.disabled = false;
})
.catch((e) => console.log(e));
};
stopRecordingBtn.onclick = () => {
let recordStatus = document.getElementById('record-status');
// Stop recording the conference
VoxeetSDK.recording.stop()
.then(() => {
recordStatus.innerText = '';
startRecordingBtn.disabled = false;
stopRecordingBtn.disabled = true;
})
.catch((e) => console.log(e));
};
// watch party
// import { initVideoController } from './video-controller.mjs';
// initVideoController(); // bring in whole script
}; // init
// Add a video stream to the web page
const addVideoNode = (participant, stream) => {
let videoNode = document.getElementById('video-' + participant.id);
if (!videoNode) {
videoNode = document.createElement('video');
// add css class to mirror current user's video
if (participant.id === VoxeetSDK.session.participant.id) {
videoNode.setAttribute('class', 'video-item flipped-video');
} else {
videoNode.setAttribute('class', 'video-item');
}
videoNode.setAttribute('id', 'video-' + participant.id);
videoNode.setAttribute("playsinline", true);
videoNode.muted = true;
// videoNode.setAttribute("autoplay", 'autoplay');
videoNode.autoplay = true;
// videoNode.controls = true;
const videoContainer = document.getElementById('video-container');
videoContainer.appendChild(videoNode);
}
navigator.attachMediaStream(videoNode, stream);
};
// Remove the video streem from the web page
const removeVideoNode = (participant) => {
let videoNode = document.getElementById('video-' + participant.id);
if (videoNode) {
videoNode.parentNode.removeChild(videoNode);
}
};
const createParticpantCard = (participant) => {
let newCard = `<li class="list-group-item-primary d-flex justify-content-between align-items-center my-list">
${participant.info.name}
<img src="${participant.info.avatarUrl}" class="img-fluid rounded-start my-list" alt="${participant.info.name}">
</li>`
return newCard;
}
// Add a new participant to the list
const addParticipantNode = (participant) => {
// If the participant is the current session user, don't add himself to the list
if (participant.id === VoxeetSDK.session.participant.id) return;
let participantNode = document.createElement('p');
participantNode.setAttribute('id', 'participant-' + participant.id);
participantNode.innerHTML = createParticpantCard(participant);
const participantsList = document.getElementById('participants-list');
participantsList.appendChild(participantNode);
};
// Remove a participant from the list
const removeParticipantNode = (participant) => {
let participantNode = document.getElementById('participant-' + participant.id);
if (participantNode) {
participantNode.parentNode.removeChild(participantNode);
}
};
// Add a screen share stream to the web page
const addScreenShareNode = (stream) => {
let screenShareNode = document.getElementById('screenshare');
if (screenShareNode) {
return alert('There is already a participant sharing a screen!');
}
screenShareNode = document.createElement('video');
screenShareNode.setAttribute('class', 'screenshare');
screenShareNode.setAttribute('id', 'screenshare');
screenShareNode.autoplay = 'autoplay';
screenShareNode.controls = true; // allows PIP and full screen
navigator.attachMediaStream(screenShareNode, stream);
const screenShareContainer = document.getElementById('screenshare-container');
screenShareContainer.appendChild(screenShareNode);
}
// Remove the screen share stream from the web page
const removeScreenShareNode = () => {
let screenShareNode = document.getElementById('screenshare');
if (screenShareNode) {
screenShareNode.parentNode.removeChild(screenShareNode);
}
const startScreenShareBtn = document.getElementById('start-screenshare-btn');
startScreenShareBtn.disabled = false;
const stopScreenShareBtn = document.getElementById('stop-screenshare-btn');
stopScreenShareBtn.disabled = true;
}
/**
*
* 1. add script just after client.js in html file
* <script type="text/javascript" src="video-controller.js"></script>
*
* Add ui to html
*
* <div id="video-clip-controls">
<label for="clip-url-input" class="form-text">Enter a video URL</label>
<input id="clip-url-input"
value="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
class="form-control" aria-describedby="clipURLHelp" />
<div class="btn-group-sm p-3">
<button type="button" class="btn btn-success" id="start-clip-btn" disabled> Begin</button>
<button type="button" class="btn btn-success" id="play-clip-btn" disabled> Play </button>
<button type="button" class="btn btn-success" id="pause-clip-btn" disabled> Pause </button>
<button type="button" class="btn btn-success" id="stop-clip-btn" disabled> End</button>
</div>
</div>
*
*
*
*
*/
// clip video Controller controls
const clipURLInput = document.getElementById('clip-url-input');
const startClipBtn = document.getElementById('start-clip-btn');
const playClipBtn = document.getElementById('play-clip-btn');
const pauseClipBtn = document.getElementById('pause-clip-btn');
const stopClipBtn = document.getElementById('stop-clip-btn');
let timestamp = 0;
// start video presentation with a url
startClipBtn.onclick = () => {
videoURL = clipURLInput.value;
VoxeetSDK.videoPresentation.start(videoURL)
.then(() => {
console.log("video started")
})
.catch((error) => {
console.log(error);
})
}
//play
playClipBtn.onclick = () => {
VoxeetSDK.videoPresentation.play()
.then(() => {
console.log("video play")
})
.catch((error) => {
console.log(error);
})
}
// pause
pauseClipBtn.onclick = () => {
VoxeetSDK.videoPresentation.pause()
.then(() => {
console.log("video pause")
})
.catch((error) => {
console.log(error);
})
}
// stop
stopClipBtn.onclick = () => {
VoxeetSDK.videoPresentation.stop()
.then(() => {
console.log("video Stop")
})
.catch((error) => {
console.log(error);
})
}
// Video Presentation listeners
VoxeetSDK.videoPresentation.on("started", (participant, stream) => {
console.log("started", participant, stream)
addClipNode(participant, stream)
startClipBtn.disabled = true;
playClipBtn.disabled = true;
pauseClipBtn.disabled = false;
stopClipBtn.disabled = false;
});
VoxeetSDK.videoPresentation.on("paused", (participant, stream) => {
console.log("paused", participant, stream)
let videoNode = document.getElementById('video-clip');
timestamp = Math.round(videoNode.currentTime * 1000);
// videoNode.currentTime = timestamp;
videoNode.pause()
startClipBtn.disabled = true;
playClipBtn.disabled = false;
pauseClipBtn.disabled = true;
stopClipBtn.disabled = false;
});
VoxeetSDK.videoPresentation.on("sought", (participant, stream) => {
let videoNode = document.getElementById('video-clip');
timestamp = Math.round(videoNode.currentTime * 1000);
// videoNode.currentTime = timestamp;
console.log("seek", participant, stream)
});
VoxeetSDK.videoPresentation.on("played", (participant, stream) => {
console.log("play", participant, stream)
let videoNode = document.getElementById('video-clip');
videoNode.play()
videoNode.muted = false;
startClipBtn.disabled = true;
playClipBtn.disabled = true;
pauseClipBtn.disabled = false;
stopClipBtn.disabled = false;
});
VoxeetSDK.videoPresentation.on("stopped", (participant, stream) => {
console.log("stopped", participant, stream);
let videoNode = document.getElementById('video-clip');
videoNode.pause()
resetRemoveVideo()
});
var resetRemoveVideo = () => {
let videoNode = document.getElementById('video-clip');
if (videoNode) {
videoNode.pause()
removeClipNode()
}
startClipBtn.disabled = false;
playClipBtn.disabled = true;
pauseClipBtn.disabled = true;
stopClipBtn.disabled = true;
}
// Add a Clip stream to the web page
const addClipNode = (participant, stream) => {
let videoNode = document.getElementById('video-clip');
if (!videoNode) {
videoNode = document.createElement('video');
videoNode.setAttribute('class', 'clip-item'); // style lager
videoNode.setAttribute('id', 'video-clip');
videoNode.setAttribute('height', 480);
videoNode.setAttribute('width', 640);
videoNode.setAttribute("playsinline", true);
videoNode.muted = false;
videoNode.setAttribute("autoplay", 'autoplay');
videoNode.setAttribute("src", participant.url);;
const videoContainer = document.getElementById('video-container');
videoContainer.prepend(videoNode)
}
navigator.attachMediaStream(videoNode, stream);
playClipBtn.disabled = false;
};
// Remove the Clip stream from the web page
const removeClipNode = () => {
let clipNode = document.getElementById('video-clip');
if (clipNode) {
clipNode.parentNode.removeChild(clipNode);
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment