-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
bd13a30
commit 4aa3cb6
Showing
3 changed files
with
443 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,236 @@ | ||
'use strict'; | ||
|
||
// non negotiable constants | ||
const av1Profile = 'video/av01.0.04M.08'; | ||
const scalabilityMode = 'L1T3'; | ||
|
||
const spatial240pVideoElement = document.getElementById('spatial-240-video'); | ||
const spatial480pVideoElement = document.getElementById('spatial-480-video'); | ||
const spatial720pVideoElement = document.getElementById('spatial-720-video'); | ||
|
||
const spatial240pRemoteVideoElement = document.getElementById('spatial-240-remote-video'); | ||
const spatial480pRemoteVideoElement = document.getElementById('spatial-480-remote-video'); | ||
const spatial720pRemoteVideoElement = document.getElementById('spatial-720-remote-video'); | ||
|
||
const spatial240pWebCodecVideoElement = document.getElementById('spatial-240-webcodec-video'); | ||
const spatial480pWebCodecVideoElement = document.getElementById('spatial-480-webcodec-video'); | ||
const spatial720pWebCodecVideoElement = document.getElementById('spatial-720-webcodec-video'); | ||
|
||
const mediaStreamTrackGenerator240p = new MediaStreamTrackGenerator({kind: 'video'}); | ||
const mediaStreamWritable240p = mediaStreamTrackGenerator240p.writable; | ||
|
||
const mediaStreamTrackGenerator480p = new MediaStreamTrackGenerator({kind: 'video'}); | ||
const mediaStreamWritable480p = mediaStreamTrackGenerator480p.writable; | ||
|
||
const mediaStreamTrackGenerator720p = new MediaStreamTrackGenerator({kind: 'video'}); | ||
const mediaStreamWritable720p = mediaStreamTrackGenerator720p.writable; | ||
|
||
|
||
let resolutions = [ | ||
{ | ||
title: "240p", | ||
width: 320, | ||
height: 240, | ||
videoElement: spatial240pVideoElement, | ||
stream: null, | ||
videoPipe: null, | ||
remoteStream: null, | ||
remoteVideoElement: spatial240pRemoteVideoElement, | ||
webCodecVideoElement: spatial240pWebCodecVideoElement, | ||
webCodecTrackGenerator: mediaStreamTrackGenerator240p, | ||
webCodecWritable: mediaStreamWritable240p, | ||
}, | ||
{ | ||
title: "480p", | ||
width: 640, | ||
height: 480, | ||
videoElement: spatial480pVideoElement, | ||
stream: null, | ||
videoPipe: null, | ||
remoteStream: null, | ||
remoteVideoElement: spatial480pRemoteVideoElement, | ||
webCodecVideoElement: spatial480pWebCodecVideoElement, | ||
webCodecTrackGenerator: mediaStreamTrackGenerator480p, | ||
webCodecWritable: mediaStreamWritable480p, | ||
}, | ||
{ | ||
title: "720p", | ||
width: 1280, | ||
height: 720, | ||
videoElement: spatial720pVideoElement, | ||
stream: null, | ||
videoPipe: null, | ||
remoteStream: null, | ||
remoteVideoElement: spatial720pRemoteVideoElement, | ||
webCodecVideoElement: spatial720pWebCodecVideoElement, | ||
webCodecTrackGenerator: mediaStreamTrackGenerator720p, | ||
webCodecWritable: mediaStreamWritable720p, | ||
}, | ||
]; | ||
|
||
const worker = new Worker('./worker.js', {name: 'E2EE worker', type: 'module'}); | ||
|
||
for (let idx = 0; idx <= resolutions.length - 1; idx++) { | ||
const {webCodecWritable: writable, title} = resolutions[idx]; | ||
|
||
worker.postMessage({ | ||
operation: `init-${title}`, | ||
writable | ||
}, [writable]) | ||
} | ||
|
||
worker.onmessage = async ({data}) => { | ||
const {operation} = data; | ||
|
||
if (operation.startsWith('track-ready')) { | ||
const resolutionMessage = operation.split('-')[2]; | ||
|
||
let idx; | ||
switch (resolutionMessage) { | ||
case '240p': | ||
idx = 0; | ||
break; | ||
|
||
case '480p': | ||
idx = 1; | ||
break; | ||
|
||
case '720p': | ||
idx = 2; | ||
break; | ||
|
||
default: | ||
throw new Error(`Unsupported resolution: ${resolutionMessage}`); | ||
} | ||
|
||
const {webCodecVideoElement, webCodecTrackGenerator} = resolutions[idx]; | ||
webCodecVideoElement.srcObject = new MediaStream([webCodecTrackGenerator]); | ||
} | ||
|
||
} | ||
|
||
document.addEventListener('keydown', (e) => { | ||
switch (e.key) { | ||
case '1': { | ||
e.preventDefault(); | ||
!startButton.disabled && start(); | ||
break; | ||
} | ||
case '2': { | ||
e.preventDefault(); | ||
!callButton.disabled && call(); | ||
break; | ||
} | ||
case '3': { | ||
e.preventDefault(); | ||
!hangupButton.disabled && hangup(); | ||
break; | ||
} | ||
default: | ||
break; | ||
} | ||
}); | ||
|
||
const startButton = document.getElementById('startButton'); | ||
const callButton = document.getElementById('callButton'); | ||
const hangupButton = document.getElementById('hangupButton'); | ||
|
||
startButton.onclick = start; | ||
callButton.onclick = call; | ||
hangupButton.onclick = hangup; | ||
|
||
async function requestLocalStream(resolution) { | ||
let {width: videoWidth, height: videoHeight, videoElement, title} = resolution; | ||
|
||
const options = { | ||
audio: false, | ||
video: {videoWidth, videoHeight} | ||
}; | ||
|
||
let stream = await navigator.mediaDevices.getUserMedia(options); | ||
console.log("Get user media: ", title, {videoWidth, videoHeight}); | ||
videoElement.srcObject = stream; | ||
resolution.stream = stream; | ||
|
||
try { | ||
const {supported, smooth, powerEfficient} = await navigator.mediaCapabilities.encodingInfo({ | ||
type: 'webrtc', | ||
video: { | ||
contentType: av1Profile, | ||
width: videoWidth, | ||
height: videoHeight, | ||
bitrate: 10000, | ||
framerate: 29.97, | ||
scalabilityMode, | ||
} | ||
}); | ||
} catch (e) { | ||
throw new Error(`Failed to configure WebRTC: ${e}`); | ||
} | ||
} | ||
|
||
async function start() { | ||
startButton.disabled = true; | ||
|
||
for (let idx = 0; idx <= resolutions.length - 1; idx++) { | ||
const resolution = resolutions[idx]; | ||
await requestLocalStream(resolution); | ||
} | ||
|
||
callButton.disabled = false; | ||
} | ||
|
||
async function call() { | ||
callButton.disabled = true; | ||
hangupButton.disabled = false; | ||
|
||
for (let idx = 0; idx <= resolutions.length - 1; idx++) { | ||
let resolution = resolutions[idx]; | ||
|
||
console.log(`localStream`, resolution.stream); | ||
|
||
resolution.videoPipe = new VideoPipe( | ||
resolution.stream, | ||
true, | ||
true, | ||
(e) => { | ||
const receiverStreams = e.receiver.createEncodedStreams(); | ||
const {readable, writable} = receiverStreams; | ||
worker.postMessage( | ||
{ | ||
operation: `decode-${resolution.title}`, | ||
readable, | ||
writable, | ||
}, [readable, writable]); | ||
|
||
console.log(`e.streams[0]`, e.streams[0]); | ||
|
||
resolution.remoteVideoElement.srcObject = e.streams[0]; | ||
}, | ||
scalabilityMode | ||
); | ||
|
||
resolution.videoPipe.pc1.getSenders().forEach((s) => { | ||
const senderStreams = s.createEncodedStreams(); | ||
const {readable, writable} = senderStreams; | ||
|
||
worker.postMessage({ | ||
operation: `encode-${resolution.title}`, | ||
readable, | ||
writable | ||
}, [readable, writable]) | ||
}); | ||
|
||
await resolution.videoPipe.negotiate(); | ||
} | ||
} | ||
|
||
async function hangup() { | ||
for (let idx = 0; idx <= resolutions.length - 1; idx++) { | ||
let resolution = resolutions[idx]; | ||
resolution.videoPipe.close(); | ||
} | ||
|
||
hangupButton.disabled = true; | ||
callButton.disabled = false; | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<title>SVC-Burrito</title> | ||
<style> | ||
.video { | ||
width: 320px; | ||
height: 240px; | ||
} | ||
</style> | ||
</head> | ||
<body style="width: 100vw;"> | ||
<div style="display: flex;"> | ||
<button id="startButton">Start (Press 1)</button> | ||
<button disabled id="callButton">Call (Press 2)</button> | ||
<button disabled id="hangupButton">Hang Up (Press 3)</button> | ||
</div> | ||
|
||
<div style="display: flex; width: 100vw;"> | ||
<div> | ||
<div>240p</div> | ||
<video autoplay class="video" id="spatial-240-video" muted playsinline></video> | ||
</div> | ||
<div> | ||
<div>480p</div> | ||
<video autoplay class="video" id="spatial-480-video" muted playsinline></video> | ||
</div> | ||
<div> | ||
<div>720p</div> | ||
<video autoplay class="video" id="spatial-720-video" muted playsinline></video> | ||
</div> | ||
</div> | ||
|
||
<div style="display: flex; width: 100vw;"> | ||
<div> | ||
<div>240p</div> | ||
<video autoplay class="video" id="spatial-240-remote-video" muted playsinline></video> | ||
</div> | ||
<div> | ||
<div>480p</div> | ||
<video autoplay class="video" id="spatial-480-remote-video" muted playsinline></video> | ||
</div> | ||
<div> | ||
<div>720p</div> | ||
<video autoplay class="video" id="spatial-720-remote-video" muted playsinline></video> | ||
</div> | ||
</div> | ||
|
||
|
||
<div style="display: flex; width: 100vw;"> | ||
<div> | ||
<div>240p</div> | ||
<video autoplay class="video" id="spatial-240-webcodec-video" muted playsinline></video> | ||
</div> | ||
<div> | ||
<div>480p</div> | ||
<video autoplay class="video" id="spatial-480-webcodec-video" muted playsinline></video> | ||
</div> | ||
<div> | ||
<div>720p</div> | ||
<video autoplay class="video" id="spatial-720-webcodec-video" muted playsinline></video> | ||
</div> | ||
</div> | ||
|
||
|
||
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script> | ||
<script src="../js/videopipe.js"></script> | ||
<script async src="./burrito.js"></script> | ||
</body> | ||
</html> |
Oops, something went wrong.