Created
June 15, 2021 14:03
-
-
Save philmillman/736486ee30fe7c35e0f892e727413ef9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<title>call methods and events demo</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1" /> | |
<script src="https://unpkg.com/@daily-co/daily-js"></script> | |
<script src="../shared-assets/create-demo-room.js"></script> | |
<style> | |
button { | |
display: block; | |
} | |
#page-blocks { | |
height: 100%; | |
display: flex; | |
flex-direction: column; | |
} | |
#page-blocks > div { | |
margin-top: 1em; | |
} | |
#create-a-room { | |
flex: none; | |
} | |
#create-a-room > div { | |
margin-top: 0.25em; | |
} | |
#meeting-info-row { | |
flex: none; | |
display: flex; | |
} | |
#meeting-info-row > div { | |
flex: auto; | |
} | |
#buttons-row { | |
flex: none; | |
display: flex; | |
} | |
#buttons-row > div { | |
flex: auto; | |
} | |
#call-frame-container { | |
flex-grow: 1; | |
/* set position and height so this is the "css container" for the iframe */ | |
position: relative; | |
height: 100%; | |
min-height: 300px; | |
} | |
.info > div { | |
margin: 0.25em; | |
} | |
.info > div:nth-of-type(2) { | |
font-size: 80%; | |
} | |
.info > div > div { | |
margin: 0.25em; | |
} | |
.flex-bins { | |
display: flex; | |
flex-basis: auto; | |
} | |
.flex-bin { | |
flex-basis: auto; | |
} | |
.disabled { | |
pointer-events: none; | |
opacity: 0.5; | |
} | |
</style> | |
</head> | |
<body onload="setup()"> | |
<script> | |
function showEvent(e) { | |
console.log('callFrame event', e); | |
} | |
function setup() { | |
// | |
// just a little ui setup | |
// | |
buttonDisable( | |
'join-meeting', | |
'join-meeting-participant', | |
'leave-meeting', | |
'toggle-local-cam', | |
'toggle-local-mic', | |
'start-recording', | |
'stop-recording', | |
'start-screenshare', | |
'stop-screenshare', | |
'subscribe-all', | |
'subscribe-none' | |
); | |
} | |
async function createRoom() { | |
// hardcode links so we can easily have non-owner and owner participants accessing the samed room | |
room = { url: 'INSERT_ROOM' }; | |
token = 'INSERT_TOKEN'; | |
ownerLink = `${room.url}?t=${token}`; | |
nonOwnerLink = room.url; | |
updateRoomInfoDisplay(); | |
setInterval(updateNetworkInfoDisplay, 5000); | |
} | |
async function createFrame() { | |
// | |
// ask the daily-js library to create an iframe inside the | |
// 'call-frame-container' div | |
// | |
let customLayout = !!document.querySelector( | |
'input[name="customLayout"]:checked' | |
).value, | |
cssFile = customLayout ? 'basics.css' : null; | |
callFrame = window.DailyIframe.createFrame( | |
document.getElementById('call-frame-container'), | |
{ | |
customLayout, | |
cssFile, | |
subscribeToTracksAutomatically: false, | |
} | |
); | |
callFrame.on('loading', (e) => { | |
showEvent(e); | |
buttonDisable('join-meeting'); | |
buttonDisable('join-meeting-participant'); | |
}); | |
callFrame | |
.on('loaded', showEvent) | |
.on('started-camera', showEvent) | |
.on('camera-error', showEvent) | |
.on('joining-meeting', showEvent) | |
.on('recording-stats', showEvent) | |
.on('recording-error', showEvent) | |
.on('app-message', showEvent) | |
.on('input-event', showEvent) | |
.on('error', showEvent); | |
callFrame.on('joined-meeting', (e) => { | |
showEvent(e); | |
buttonEnable( | |
'leave-meeting', | |
'toggle-local-cam', | |
'toggle-local-mic', | |
'start-recording', | |
'start-screenshare', | |
'subscribe-all', | |
'subscribe-none' | |
); | |
subscribeToOwnerTracks(); | |
}); | |
callFrame.on('left-meeting', (e) => { | |
showEvent(e); | |
buttonDisable( | |
'leave-meeting', | |
'toggle-local-cam', | |
'toggle-local-mic', | |
'start-recording', | |
'stop-recording', | |
'start-screenshare', | |
'stop-screenshare', | |
'subscribe-all', | |
'subscribe-none' | |
); | |
buttonEnable('join-meeting'); | |
buttonEnable('join-meeting-participant'); | |
}); | |
callFrame.on('recording-started', (e) => { | |
showEvent(e); | |
buttonDisable('start-recording'); | |
buttonEnable('stop-recording'); | |
}); | |
callFrame.on('recording-stopped', (e) => { | |
showEvent(e); | |
buttonEnable('start-recording'); | |
buttonDisable('stop-recording'); | |
}); | |
callFrame | |
.on('participant-joined', participantJoined) | |
.on('participant-updated', updateParticipantInfoDisplay) | |
.on('participant-left', updateParticipantInfoDisplay); | |
} | |
async function createFrameAndRoom() { | |
document.getElementById('create-a-room').style.display = 'none'; | |
await createRoom(); | |
await createFrame(); | |
buttonEnable('join-meeting'); | |
buttonEnable('join-meeting-participant'); | |
} | |
function updateRoomInfoDisplay() { | |
let roomInfo = document.getElementById('meeting-room-info'); | |
roomInfo.innerHTML = ` | |
<div><b>room info</b></div> | |
<div> | |
send to invite or click to join | |
<div><a href="${room.url}" target="_blank"> | |
${room.url.replace('.co/', '.co/​')} | |
</a></div> | |
<div id='expires-countdown'></div> | |
</div> | |
`; | |
if (!window.expiresUpdate) { | |
window.expiresUpdate = setInterval(() => { | |
let exp = room && room.config && room.config.exp; | |
if (exp) { | |
document.getElementById('expires-countdown').innerHTML = ` | |
room expires in | |
${Math.floor((new Date(exp * 1000) - Date.now()) / 1000)} | |
seconds | |
`; | |
} | |
}, 1000); | |
} | |
} | |
function participantJoined(e) { | |
// subscribe to latest participant | |
callFrame.updateParticipant( | |
e.participant.session_id, | |
{ | |
setSubscribedTracks: true | |
} | |
); | |
// unsubscribe from latest after 30 seconds if they aren't an owner | |
if (!e.participant.owner) { | |
setTimeout( () => { | |
callFrame.updateParticipant( | |
e.participant.session_id, | |
{ | |
setSubscribedTracks: false | |
} | |
); | |
}, 30000) | |
} | |
updateParticipantInfoDisplay(e); | |
} | |
function subscribeToOwnerTracks() { | |
const participants = callFrame.participants(); | |
let idsToBeSubscribed = []; | |
// add non local owners to to-be-subscribed list | |
for (let id in participants) { | |
let p = participants[id] | |
if (p.owner === true && p.local === false) { | |
idsToBeSubscribed.push(participants[id].session_id); | |
} | |
} | |
// subscribe to list | |
idsToBeSubscribed.forEach((id) => { | |
callFrame.updateParticipant( | |
id, | |
{ | |
setSubscribedTracks: true | |
} | |
); | |
}) | |
} | |
function updateParticipantInfoDisplay(e) { | |
showEvent(e); | |
let infoEl = document.getElementById('meeting-participants-info'), | |
participants = callFrame.participants(), | |
infoHTML = ''; | |
// look and make an info block for each participant | |
for (var id in participants) { | |
let p = participants[id]; | |
infoHTML += ` | |
<div> | |
<div>${p.user_name || 'guest'}</div> | |
<div>cam ${p.video ? 'on' : 'off'}</div> | |
<div>mic ${p.audio ? 'on' : 'off'}</div> | |
</div> | |
`; | |
} | |
infoEl.innerHTML = | |
'<div><b>meeting participants</b></div>' + | |
'<div>' + | |
infoHTML + | |
'</div>'; | |
// update local screenshare button state | |
if (participants.local) { | |
if (participants.local.screen) { | |
buttonDisable('start-screenshare'); | |
buttonEnable('stop-screenshare'); | |
} else { | |
buttonDisable('stop-screenshare'); | |
buttonEnable('start-screenshare'); | |
} | |
} | |
} | |
async function updateNetworkInfoDisplay() { | |
let infoEl = document.getElementById('network-info'), | |
statsInfo = await callFrame.getNetworkStats(); | |
infoEl.innerHTML = ` | |
<div><b>network stats</b></div> | |
<div> | |
<div> | |
video send: | |
${Math.floor(statsInfo.stats.latest.videoSendBitsPerSecond / 1000)} kb/s | |
</div> | |
<div> | |
video recv: | |
${Math.floor(statsInfo.stats.latest.videoRecvBitsPerSecond / 1000)} kb/s | |
<div> | |
worst send packet loss: | |
${Math.floor(statsInfo.stats.worstVideoSendPacketLoss * 100)}%</div> | |
<div>worst recv packet loss: | |
${Math.floor(statsInfo.stats.worstVideoRecvPacketLoss * 100)}%</div> | |
</div> | |
`; | |
} | |
function toggleCam() { | |
callFrame.setLocalVideo(!callFrame.participants().local.video); | |
} | |
function toggleMic() { | |
callFrame.setLocalAudio(!callFrame.participants().local.audio); | |
} | |
// | |
// UI utility functions | |
// | |
function buttonEnable(...args) { | |
args.forEach((id) => { | |
let el = document.getElementById(id); | |
if (el) { | |
el.classList.remove('disabled'); | |
} | |
}); | |
} | |
function buttonDisable(...args) { | |
args.forEach((id) => { | |
let el = document.getElementById(id); | |
if (el) { | |
el.classList.add('disabled'); | |
} | |
}); | |
} | |
</script> | |
<div id="page-blocks"> | |
<div id="create-a-room"> | |
<button onclick="createFrameAndRoom()">create a room</button> | |
<div> | |
<label> | |
<input type="radio" name="customLayout" value="" checked /> | |
standard Daily.co UI | |
</label> | |
</div> | |
<div> | |
<label> | |
<input type="radio" name="customLayout" value="true" /> | |
demo custom UI | |
</label> | |
</div> | |
</div> | |
<div id="meeting-info-row"> | |
<div id="meeting-room-info" class="info"> | |
room info | |
</div> | |
<div id="meeting-participants-info" class="info"> | |
meeting participants | |
</div> | |
<div id="network-info" class="info"> | |
network stats | |
</div> | |
</div> | |
<div id="buttons-row"> | |
<div> | |
<button | |
id="join-meeting" | |
onclick="callFrame.join({ url: ownerLink })" | |
> | |
join meeting (as owner) | |
</button> | |
<button | |
id="join-meeting-participant" | |
onclick="callFrame.join({ url: nonOwnerLink })" | |
> | |
join meeting (as participant) | |
</button> | |
<button id="leave-meeting" onclick="callFrame.leave()"> | |
leave meeting | |
</button> | |
</div> | |
<div> | |
<button id="toggle-local-cam" onclick="toggleCam()"> | |
toggle local cam | |
</button> | |
<button id="toggle-local-mic" onclick="toggleMic()"> | |
toggle local mic | |
</button> | |
</div> | |
<div> | |
<button | |
id="start-recording" | |
onclick="buttonDisable('start-recording'); | |
callFrame.startRecording()" | |
> | |
start recording | |
</button> | |
<button id="stop-recording" onclick="callFrame.stopRecording()"> | |
stop recording | |
</button> | |
</div> | |
<div> | |
<button id="start-screenshare" onclick="callFrame.startScreenShare()"> | |
start screenshare | |
</button> | |
<button id="stop-screenshare" onclick="callFrame.stopScreenShare()"> | |
stop screenshare | |
</button> | |
</div> | |
<div> | |
<button | |
id="subscribe-all" | |
onclick="callFrame.setSubscribeToTracksAutomatically(true)" | |
title="subscribe to all media tracks" | |
> | |
subscribe | |
</button> | |
<button | |
id="subscribe-none" | |
onclick="callFrame.setSubscribeToTracksAutomatically(false)" | |
title="unsubscribe from all media tracks" | |
> | |
unsubscribe | |
</button> | |
</div> | |
</div> | |
<div id="call-frame-container"></div> | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment