Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
A
awrtc
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Иван Кубота
awrtc
Commits
4d232112
Commit
4d232112
authored
Sep 24, 2021
by
Иван Кубота
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
all changes
parent
0d5e5afd
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
753 additions
and
423 deletions
+753
-423
app.js
build/app.js
+5
-407
favicon.png
build/favicon.png
+0
-0
back.jpg
build/img/back.jpg
+0
-0
segmentrtc.html
build/segmentrtc.html
+155
-8
CallScreen.js
build/view/CallScreen.js
+365
-0
CanvasResizer.js
build/view/CanvasResizer.js
+57
-0
Input.js
build/view/Input.js
+27
-0
MainScreen.js
build/view/MainScreen.js
+37
-0
Screen.js
build/view/Screen.js
+13
-0
Select.js
build/view/Select.js
+54
-0
canvasResizer.css
build/view/canvasResizer.css
+25
-0
videoinputapp.ts
src/apps/videoinputapp.ts
+15
-8
No files found.
build/app.js
View file @
4d232112
let
content
,
remoteVideoEl
;
let
content
,
remoteVideoEl
;
const
store
=
window
.
store
=
new
Store
({
const
store
=
window
.
store
=
new
Store
({
conference_id
:
'
SelfieBarracuda_con
'
,
conference_id
:
'
LUCID-4
'
,
connection
:
false
,
connection
:
false
,
webcam1
:
'Center'
,
webcam2
:
'Right'
,
webcamtypes
:
[
webcamtypes
:
[
{
text
:
'Left'
,
value
:
'Left'
},
{
text
:
'Right'
,
value
:
'Right'
},
{
text
:
'Center'
,
value
:
'Center'
},
{
text
:
'Center'
,
value
:
'Center'
},
{
text
:
'Right'
,
value
:
'Right'
},
{
text
:
'Left'
,
value
:
'Left'
},
],
],
userRoles
:
[
userRoles
:
[
{
text
:
'Remote User'
,
value
:
'RemoteUser'
},
{
text
:
'Remote User'
,
value
:
'RemoteUser'
},
{
text
:
'Office User Left'
,
value
:
'OfficeUserLeft'
},
{
text
:
'Office User Right'
,
value
:
'OfficeUserRight'
},
{
text
:
'Office User Right'
,
value
:
'OfficeUserRight'
},
{
text
:
'Office User Left'
,
value
:
'OfficeUserLeft'
},
],
],
userRole1
:
'RemoteUser'
,
userRole2
:
'OfficeUserRight'
});
});
const
Input
=
function
(
cfg
,
bind
)
{
cfg
.
onkeyup
=
cfg
.
oninput
=
cfg
.
onchange
=
function
()
{
store
.
set
(
bind
,
input
.
value
);
};
var
input
=
D
.
h
(
'input'
,
cfg
);
store
.
sub
(
bind
,
function
(
val
)
{
input
.
value
=
val
;
});
return
input
;
};
const
LabeledInput
=
function
(
cfg
,
bind
)
{
return
D
.
h
(
'label'
,
{},
D
.
div
.
apply
(
D
,
[{
cls
:
'label_label'
}].
concat
(
cfg
.
label
)),
Input
(
cfg
,
bind
)
)
}
const
isConnected
=
new
Store
.
Value
.
Boolean
(
false
);
const
isConnected
=
new
Store
.
Value
.
Boolean
(
false
);
store
.
sub
(
'connection'
,
function
(
val
)
{
store
.
sub
(
'connection'
,
function
(
val
)
{
isConnected
.
set
(
val
)
isConnected
.
set
(
val
)
});
});
var
Select
=
function
(
cfg
)
{
Screen
.
show
(
'Main'
);
let
isOpen
=
this
.
isOpen
=
new
Store
.
Value
.
Boolean
(
false
);
var
table
=
D
.
div
({
cls
:
'dropdown-list'
},
_
=>
{
store
.
sub
(
cfg
.
values
,
function
(
val
)
{
if
(
val
){
_
(
val
.
map
(
function
(
v
)
{
return
D
.
div
({
cls
:
'dropdown-item'
,
'data-id'
:
v
.
value
,
onclick
:
function
()
{
cfg
.
bind
.
set
(
v
.
value
);
isOpen
.
set
(
false
);
}},
v
.
text
)
}));
}
});
});
var
dom
=
D
.
div
({
cls
:
'form-field'
},
D
.
div
({
cls
:
'form-field__label'
},
D
.
span
({
cls
:
'form-field__label-text'
},
cfg
.
label
),
D
.
div
({
cls
:
[
'dropdown-field'
,
{
'dropdown-field--opened'
:
isOpen
}]},
D
.
h
(
'button'
,
{
cls
:
'dropdown-field__toggler'
,
onclick
:
()
=>
isOpen
.
toggle
()
},
D
.
span
({
cls
:
D
.
cls
(
"dropdown-field__placeholder"
,
{
"dropdown-field__placeholder--filled"
:
_
=>
cfg
.
bind
.
sub
(
val
=>
_
(
!!
(
cfg
.
multivalue
?
val
&&
val
.
length
:
val
&&
val
.
name
)))
}
)},
_
=>
{
cfg
.
bind
.
sub
(
val
=>
{
if
(
val
){
var
vals
=
store
.
get
(
cfg
.
values
)
||
[],
theVal
=
vals
.
filter
(
v
=>
v
.
value
===
val
)[
0
];
_
(
theVal
?
theVal
.
text
:
'Select'
)
}
else
{
_
(
cfg
.
placeholder
);
}
}
);
}
)
),
D
.
div
({
cls
:
'dropdown-field__tooltip'
},
table
)
)
)
);
return
dom
;
}
var
camera1canvas
,
camera2canvas
,
single
=
new
Store
.
Value
.
Boolean
(
true
);
D
.
div
({
cls
:
'top-bar'
,
renderTo
:
document
.
body
},
D
.
h
(
'img'
,
{
src
:
'amazon-logo.svg'
}),
D
.
div
({
cls
:
'buttons'
},
D
.
h
(
'button'
,
{
cls
:
[
'button secondary'
,
{
hidden
:
Store
.
NOT
(
isConnected
)}],
onclick
:
()
=>
store
.
set
(
'connection'
,
false
)},
'End session'
),
D
.
h
(
'button'
,
{
cls
:
[
'button primary'
,
{
hidden
:
isConnected
}],
onclick
:
()
=>
store
.
set
(
'connection'
,
true
)},
'Ready to connect'
)
),
content
=
D
.
div
({
cls
:
'content'
},
D
.
div
({
cls
:
'block'
},
D
.
div
({
cls
:
'header'
},
'Cameras'
),
Select
({
values
:
'videoinput'
,
bind
:
store
.
bind
(
'videoinput1'
),
label
:
'Camera 1'
}),
Select
({
values
:
'webcamtypes'
,
bind
:
store
.
bind
(
'webcam1'
),
label
:
'WebCam'
}),
Select
({
values
:
'userRoles'
,
bind
:
store
.
bind
(
'userRole1'
),
label
:
'User role'
}),
camera1canvas
=
D
.
h
(
'canvas'
,
{
cls
:
"output_canvas"
,
width
:
"640px"
,
height
:
"480px"
,
style
:
{
/*display: 'none',*/
width
:
'320px'
}
}),
D
.
div
({},
D
.
h
(
'button'
,
{
cls
:
'switch-button'
,
onclick
:
_
=>
single
.
toggle
()},
_
=>
single
.
hook
(
val
=>
_
(
val
?
'Duo'
:
'Single'
))
),
),
D
.
div
({
cls
:
[{
hidden
:
single
}]},
Select
({
values
:
'videoinput'
,
bind
:
store
.
bind
(
'videoinput2'
),
label
:
'Camera 2'
}),
Select
({
values
:
'webcamtypes'
,
bind
:
store
.
bind
(
'webcam2'
),
label
:
'WebCam'
}),
Select
({
values
:
'userRoles'
,
bind
:
store
.
bind
(
'userRole2'
),
label
:
'User role'
}),
camera2canvas
=
D
.
h
(
'canvas'
,
{
cls
:
"output_canvas"
,
width
:
"640px"
,
height
:
"480px"
,
style
:
{
/*display: 'none',*/
width
:
'320px'
}
})
),
),
D
.
div
({
cls
:
'block'
},
D
.
div
({
cls
:
'header'
},
'Conference info'
),
LabeledInput
({
label
:
'Session ID'
,
cls
:
'callapp_address input'
,
autocomplete
:
'off'
,
value
:
'SelfieBarracuda_con'
},
'conference_id'
),
),
D
.
div
({
cls
:
[
'block'
,
{
hidden
:
true
}]},
//Store.NOT(isConnected)
D
.
div
({
cls
:
[
'header'
]},
'Remote video'
),
remoteVideoEl
=
window
.
remoteVideoEl
=
D
.
div
({
cls
:
'remote-video'
})
)
)
);
var
streams
=
{};
var
video1
=
D
.
h
(
'video'
);
var
video2
=
D
.
h
(
'video'
);
var
camera1canvasCtx
=
camera1canvas
.
getContext
(
'2d'
);
var
camera2canvasCtx
=
camera2canvas
.
getContext
(
'2d'
);
var
updateVideos
=
function
()
{
camera1canvasCtx
.
drawImage
(
video1
,
0
,
0
);
if
(
!
single
.
get
()){
camera2canvasCtx
.
drawImage
(
video2
,
0
,
0
);
}
requestAnimationFrame
(
updateVideos
);
};
requestAnimationFrame
(
updateVideos
);
store
.
sub
([
'videoinput1'
,
'videoinput2'
],
async
(
input1
,
input2
)
=>
{
await
Promise
.
all
([
input1
,
input2
].
map
(
async
function
(
val
,
i
)
{
if
(
val
){
try
{
if
(
val
in
streams
){
stream
=
streams
[
val
];
}
else
{
var
stream
=
await
navigator
.
mediaDevices
.
getUserMedia
(
{
video
:
{
deviceId
:
{
exact
:
val
}
}
}
);
}
streams
[
val
]
=
stream
;
var
video
=
[
video1
,
video2
][
i
];
video
.
srcObject
=
stream
;
video
.
play
();
console
.
log
(
'2'
,
+
new
Date
());
}
catch
(
e
){
console
.
error
(
e
)
}
}
for
(
var
i
in
streams
){
if
(
i
!==
input1
&&
i
!==
input2
){
var
stream
=
streams
[
i
];
stream
.
getTracks
().
forEach
(
function
(
track
)
{
track
.
stop
();
});
}
}
}));
});
function
gotDevices
(
deviceInfos
)
{
// Handles being called several times to update labels. Preserve values.
var
devices
=
{
audioinput
:
[],
audiooutput
:
[],
videoinput
:
[]};
for
(
let
i
=
0
;
i
!==
deviceInfos
.
length
;
++
i
)
{
const
deviceInfo
=
deviceInfos
[
i
];
const
option
=
{
value
:
deviceInfo
.
deviceId
};
if
(
!
(
deviceInfo
.
kind
in
devices
)){
devices
[
deviceInfo
.
kind
]
=
[];
}
devices
[
deviceInfo
.
kind
].
push
(
option
);
var
count
=
devices
[
deviceInfo
.
kind
].
length
;
if
(
deviceInfo
.
kind
===
'audioinput'
)
{
option
.
text
=
deviceInfo
.
label
||
`microphone
${
count
}
`
;
}
else
if
(
deviceInfo
.
kind
===
'audiooutput'
)
{
option
.
text
=
deviceInfo
.
label
||
`speaker
${
count
}
`
;
}
else
if
(
deviceInfo
.
kind
===
'videoinput'
)
{
option
.
text
=
deviceInfo
.
label
||
`camera
${
count
}
`
;
}
else
{
console
.
log
(
'Some other kind of source/device: '
,
deviceInfo
);
}
}
store
.
set
(
'videoinput'
,
devices
.
videoinput
);
store
.
set
(
'videoinput1'
,
devices
.
videoinput
[
devices
.
videoinput
.
length
-
1
].
value
);
store
.
set
(
'videoinput2'
,
devices
.
videoinput
[
devices
.
videoinput
.
length
-
2
].
value
);
console
.
log
(
devices
);
/*const values = selectors.map(select => select.value);
selectors.forEach(select => {
while (select.firstChild) {
select.removeChild(select.firstChild);
}
});
for (let i = 0; i !== deviceInfos.length; ++i) {
const deviceInfo = deviceInfos[i];
const option = document.createElement('option');
option.value = deviceInfo.deviceId;
if (deviceInfo.kind === 'audioinput') {
option.text = deviceInfo.label || `microphone ${audioInputSelect.length + 1}`;
audioInputSelect.appendChild(option);
} else if (deviceInfo.kind === 'audiooutput') {
option.text = deviceInfo.label || `speaker ${audioOutputSelect.length + 1}`;
audioOutputSelect.appendChild(option);
} else if (deviceInfo.kind === 'videoinput') {
option.text = deviceInfo.label || `camera ${videoSelect.length + 1}`;
videoSelect.appendChild(option);
} else {
console.log('Some other kind of source/device: ', deviceInfo);
continue;
}
}
selectors.forEach((select, selectorIndex) => {
if (Array.prototype.slice.call(select.childNodes).some(n => n.value === values[selectorIndex])) {
select.value = values[selectorIndex];
}
});*/
}
var
handleError
=
function
(
e
)
{
console
.
log
(
'Error'
,
e
)
}
var
RTC
=
function
(
parent
,
canvas
,
devname
,
id
)
{
let
callApp
;
console
.
log
(
"init callapp"
);
if
(
parent
==
null
)
{
console
.
log
(
"parent was null"
);
parent
=
document
.
body
;
}
awrtc
.
SLog
.
SetLogLevel
(
awrtc
.
SLogLevel
.
Info
);
callApp
=
new
apps
.
VideoInputApp
();
const
media
=
new
awrtc
.
Media
();
awrtc
.
Media
.
SharedInstance
.
VideoInput
.
AddCanvasDevice
(
canvas
,
devname
,
canvas
.
width
/
2
,
canvas
.
height
/
2
,
30
);
setInterval
(()
=>
{
awrtc
.
Media
.
SharedInstance
.
VideoInput
.
UpdateFrame
(
devname
);
},
50
);
//apps.VideoInputApp.sVideoDevice = devname;
callApp
.
sVideoDevice
=
devname
;
callApp
.
setupUi
(
parent
);
this
.
callApp
=
callApp
;
callApp
.
___id
=
id
;
this
.
id
=
id
;
}
let
instance1
,
instance2
;
store
.
sub
(
'appLoaded'
,
function
(
loaded
)
{
if
(
!
loaded
)
return
;
instance1
=
new
RTC
(
document
.
querySelector
(
"#videoinputapp1"
),
camera1canvas
,
'canvas1'
,
1
);
instance1
.
mUiRemoteVideoParent
=
remoteVideoEl
;
instance2
=
new
RTC
(
document
.
querySelector
(
"#videoinputapp1"
),
camera2canvas
,
'canvas2'
,
2
);
instance2
.
mUiRemoteVideoParent
=
remoteVideoEl
;
const
selfieSegmentation1
=
new
SelfieSegmentation
(
{
locateFile
:
(
file
)
=>
{
return
`https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation/
${
file
}
`
;
}
}
);
selfieSegmentation1
.
setOptions
(
{
modelSelection
:
1
,
}
);
selfieSegmentation1
.
onResults
(
function
(){
window
.
onResult1
.
apply
(
this
,
arguments
)
}
);
const
selfieSegmentation2
=
new
SelfieSegmentation
(
{
locateFile
:
(
file
)
=>
{
return
`https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation/
${
file
}
`
;
}
}
);
selfieSegmentation2
.
setOptions
(
{
modelSelection
:
1
,
}
);
selfieSegmentation2
.
onResults
(
function
(){
window
.
onResult2
.
apply
(
this
,
arguments
)
}
);
var
segmentation
=
async
function
()
{
if
(
video1
.
videoWidth
>
10
&&
store
.
get
(
'videoinput1'
)){
//debugger
await
selfieSegmentation1
.
send
(
{
image
:
video1
}
);
//camera1canvasCtx.drawImage(selfieSegmentation1.g.l,0,0)
}
if
(
single
.
get
()
===
false
&&
video2
.
videoWidth
>
10
&&
store
.
get
(
'videoinput2'
)){
//debugger
await
selfieSegmentation2
.
send
(
{
image
:
video2
}
);
//camera1canvasCtx.drawImage(selfieSegmentation1.g.l,0,0)
}
requestAnimationFrame
(
segmentation
);
};
requestAnimationFrame
(
segmentation
);
});
var
resultProcessor
=
function
(
canvasElement
)
{
window
.
canvasElement
=
canvasElement
;
const
segmentations
=
[
false
,
false
,
false
,
false
];
let
sPointer
=
0
;
var
w
=
720
,
h
=
405
;
var
tmpCanvas
=
D
.
h
(
'canvas'
,
{
width
:
w
,
height
:
h
}),
tmpCtx
=
tmpCanvas
.
getContext
(
'2d'
),
composedMaskCanvas
=
D
.
h
(
'canvas'
,
{
width
:
w
,
height
:
h
}),
composedMaskCtx
=
composedMaskCanvas
.
getContext
(
'2d'
),
composedData
=
composedMaskCtx
.
getImageData
(
0
,
0
,
w
,
h
),
composedDataData
=
composedData
.
data
;
const
canvasCtx
=
window
.
canvasCtx
=
canvasElement
.
getContext
(
'2d'
);
return
function
(
results
){
var
max
=
Math
.
max
;
var
image
=
results
.
segmentationMask
;
tmpCtx
.
clearRect
(
0
,
0
,
w
,
h
);
tmpCtx
.
drawImage
(
image
,
0
,
0
,
image
.
width
,
image
.
height
,
0
,
0
,
w
,
h
);
segmentations
[(
sPointer
++
)
%
4
]
=
tmpCtx
.
getImageData
(
0
,
0
,
w
,
h
).
data
;
if
(
sPointer
>
3
){
for
(
var
i
=
3
,
_i
=
h
*
w
*
4
;
i
<
_i
;
i
+=
4
){
//if( ){
composedDataData
[
i
]
=
composedDataData
[
i
-
1
]
=
segmentations
[
3
][
i
]
+
segmentations
[
2
][
i
]
+
segmentations
[
1
][
i
]
+
segmentations
[
0
][
i
]
>
120
?
0
:
255
;
//}
}
composedMaskCtx
.
putImageData
(
composedData
,
0
,
0
);
}
canvasCtx
.
drawImage
(
results
.
image
,
0
,
0
,
canvasElement
.
width
,
canvasElement
.
height
);
canvasCtx
.
drawImage
(
composedMaskCanvas
/*results.segmentationMask*/
,
0
,
0
,
canvasElement
.
width
,
canvasElement
.
height
);
};
}
window
.
onResult1
=
resultProcessor
(
document
.
getElementsByClassName
(
'output_canvas'
)[
0
]
);
window
.
onResult2
=
resultProcessor
(
document
.
getElementsByClassName
(
'output_canvas'
)[
1
]
);
//gotDevices([{"deviceId":"default","kind":"audioinput","label":"Default - Microphone (2- Razer Kiyo) (1532:0e03)","groupId":"c9b2965558c8600ceaa11c06017152dc99f8721fef0585ad9432838b46f8f9f7"},{"deviceId":"communications","kind":"audioinput","label":"Communications - Microphone (2- Razer Kiyo) (1532:0e03)","groupId":"c9b2965558c8600ceaa11c06017152dc99f8721fef0585ad9432838b46f8f9f7"},{"deviceId":"1517d03bc4bc8e08292b02b454b79e3a93f39fa14d7c589c47c80d093093ed1e","kind":"audioinput","label":"Microphone (Steam Streaming Microphone)","groupId":"20a28b389c696bd36556474101f44876ee56f686b3717913354b85fa804c8c7a"},{"deviceId":"b963d76466dcc0490a58d9624e987a3e69d689c2529adf66f39efae8fccd031c","kind":"audioinput","label":"Microphone (Razer Kiyo) (1532:0e03)","groupId":"ea58a01565e810e30b4d7873050388edb9dc43a11007253ecc9dabd4201230fd"},{"deviceId":"3a664d8417e7000b78f8619667da3e38280269edb222a74d1375786e9c8e70d3","kind":"audioinput","label":"Mic in at rear panel (Pink) (Realtek(R) Audio)","groupId":"8e1aab63dd80f414dce561f4e368bb484c065834f3941db045ca722f61d254a4"},{"deviceId":"46ac5b427bdd38a095664fe7e817a5e7fb7cd2a7077558e72112ade79f27f3a5","kind":"audioinput","label":"Microphone (2- Razer Kiyo) (1532:0e03)","groupId":"c9b2965558c8600ceaa11c06017152dc99f8721fef0585ad9432838b46f8f9f7"},{"deviceId":"78f07683774a206866fdb098d8cac2cb5afc980ba3e670f85393eb16d5e914b9","kind":"audioinput","label":"Headset Microphone (Oculus Virtual Audio Device)","groupId":"05a90cf47adb203e6eb67353f82529c636dc92833ed13f011042a32a370c44c7"},{"deviceId":"68cb94c20ca0b8f17bbaad703c76cbce402793b5e18ddc89e68f38865ed82478","kind":"videoinput","label":"Intel(R) RealSense(TM) 435 with RGB Module Depth (8086:0b07)","groupId":"eb53f0590ee544f7848664d5e2ac6c8430659c4a34e26edf401b57fd9a8ce83c"},{"deviceId":"943c211869cd4e58039d142e22b98ca0cc53dc4d7f60723c832cf73b52b49d6f","kind":"videoinput","label":"Intel(R) RealSense(TM) 435 with RGB Module RGB (8086:0b07)","groupId":"16dd5ec91babf1e3d461bb5afe04bd4713b0c95d3c538ea6f3515dc5c3aacb9a"},{"deviceId":"0329d90dd74edc8657af0bb0d32652989fb1c162d0c294794cbc7fd76e4cf9a9","kind":"videoinput","label":"USB Video Device (1532:0e03)","groupId":"a5fe4973e22ce5b529b8cccd14ce14ed356709d356c94228cb5c2e77d804f297"},{"deviceId":"426bd00749eecdb8ce1da28ecae7d99e78310cc57aedbdf947e9288f4660ad12","kind":"videoinput","label":"USB Video Device (1532:0e03)","groupId":"1b4fc078561da2a5b19c21531d27485fa6f19368d8440d2740d94809c3b5da84"},{"deviceId":"default","kind":"audiooutput","label":"Default - Speakers (Realtek(R) Audio)","groupId":"8e1aab63dd80f414dce561f4e368bb484c065834f3941db045ca722f61d254a4"},{"deviceId":"communications","kind":"audiooutput","label":"Communications - Headphones (Oculus Virtual Audio Device)","groupId":"05a90cf47adb203e6eb67353f82529c636dc92833ed13f011042a32a370c44c7"},{"deviceId":"7c5103d23dc4e21fb0c436dbf039909bc2c70611a92587da582edd74bbee8460","kind":"audiooutput","label":"PHL BDM3490 (NVIDIA High Definition Audio)","groupId":"731a927b663a4a209a3359d16c1c1f214ded54c07f084f659ff4809e6cf588d5"},{"deviceId":"218fa70f234dbf497b6044345c531d15120f56a49e872e3062a0d9da11f8d158","kind":"audiooutput","label":"Speakers (Steam Streaming Microphone)","groupId":"20a28b389c696bd36556474101f44876ee56f686b3717913354b85fa804c8c7a"},{"deviceId":"11c4193f457b6e9cfa44f88fa6742d8a151ce7dfd8bd71b8fd97d0f5b664a6ec","kind":"audiooutput","label":"DELL U2715H (NVIDIA High Definition Audio)","groupId":"4cd1fd9ed5fe4bb80fe7984a3c60e472548f37e157239e4d901ffe8394af5205"},{"deviceId":"f9893c7a1ce8fd1f229a37d8963f9db9504c03cff47e173bc4f1ab4ee20696db","kind":"audiooutput","label":"Headphones (Oculus Virtual Audio Device)","groupId":"05a90cf47adb203e6eb67353f82529c636dc92833ed13f011042a32a370c44c7"},{"deviceId":"c611d06286b441cb1e3440e9bf09f534d98b4ed2e41528eb9c54cb7e41779c63","kind":"audiooutput","label":"Speakers (Steam Streaming Speakers)","groupId":"4d0e12aa90d61a5867f01beea961e77cb03796fd77a2c8cde7f25ec82b718ee9"},{"deviceId":"e00a5fe0a89b8c5bd2858060265e9b0937249601678974e5f3180f797e99ef9e","kind":"audiooutput","label":"Speakers (Realtek(R) Audio)","groupId":"8e1aab63dd80f414dce561f4e368bb484c065834f3941db045ca722f61d254a4"},{"deviceId":"e29c7603a6e3b56aaf3ffc5535f563dd2bce09ce208722837aecee06eaf358d9","kind":"audiooutput","label":"Realtek Digital Output (Realtek(R) Audio)","groupId":"7ae806bf56274db2fab2c6c03a14eed45022de19176702d33821bb7c8e436e8d"}])
(
async
function
()
{
try
{
var
permissionObj
=
await
navigator
.
permissions
.
query
(
{
name
:
'microphone'
}
)
console
.
log
(
permissionObj
.
state
);
}
catch
(
error
){
console
.
log
(
'Got error :'
,
error
);
}
try
{
var
permissionObj
=
await
navigator
.
permissions
.
query
(
{
name
:
'camera'
}
)
console
.
log
(
permissionObj
.
state
);
}
catch
(
error
){
console
.
log
(
'Got error :'
,
error
);
}
navigator
.
mediaDevices
.
enumerateDevices
().
then
(
gotDevices
).
catch
(
handleError
);
setInterval
(
function
()
{
D
(
'video'
).
map
(
a
=>
a
.
muted
=
true
)
},
2000
);
})();
...
...
build/favicon.png
0 → 100644
View file @
4d232112
515 Bytes
build/img/back.jpg
0 → 100644
View file @
4d232112
356 KB
build/segmentrtc.html
View file @
4d232112
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<html>
<head>
<head>
<link
rel=
"icon"
type=
"image/png"
href=
"favicon.png"
>
<meta
charset=
"utf-8"
>
<meta
charset=
"utf-8"
>
<script
src=
"https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils/camera_utils.js"
crossorigin=
"anonymous"
></script>
<script
src=
"https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils/camera_utils.js"
crossorigin=
"anonymous"
></script>
<script
src=
"https://cdn.jsdelivr.net/npm/@mediapipe/control_utils/control_utils.js"
crossorigin=
"anonymous"
></script>
<script
src=
"https://cdn.jsdelivr.net/npm/@mediapipe/control_utils/control_utils.js"
crossorigin=
"anonymous"
></script>
...
@@ -8,12 +11,58 @@
...
@@ -8,12 +11,58 @@
<script
src=
"https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation/selfie_segmentation.js"
crossorigin=
"anonymous"
></script>
<script
src=
"https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation/selfie_segmentation.js"
crossorigin=
"anonymous"
></script>
<script
src=
"https://form.dev/vanilla/build/rDOM_latest.js"
></script>
<script
src=
"https://form.dev/vanilla/build/rDOM_latest.js"
></script>
<style>
<style>
@font-face
{
font-family
:
"Amazon Ember"
;
src
:
url("font/AmazonEmber_W_Bd.woff2")
,
url("font/AmazonEmber_W_Bd.woff")
;
font-weight
:
bold
;
}
@font-face
{
font-family
:
"Amazon Ember"
;
src
:
url("font/AmazonEmber_W_Rg.woff2")
,
url("font/AmazonEmber_W_Rg.woff")
;
font-weight
:
normal
;
}
*
{
*
{
font-family
:
Verdana
;
font-family
:
"Amazon Ember"
,
Verdana
;
}
img
.logo
{
position
:
absolute
;
top
:
40px
;
left
:
40px
;
}
html
{
height
:
100%
;
}
}
.main-content
{
.main-content
{
margin
:
16px
0
;
margin
:
16px
0
;
}
}
#content
{
height
:
100%
;
position
:
relative
;
}
.main-background
{
height
:
100%
;
background
:
url(/img/back.jpg)
;
background-size
:
cover
;
background-position-x
:
center
;
}
.main-background
:before
{
content
:
''
;
position
:
absolute
;
left
:
0
;
top
:
0
;
background
:
rgba
(
0
,
0
,
0
,
0.5
);
right
:
0
;
bottom
:
0
;
}
.main-background
.p
,
.main-background
.h1
{
color
:
#fff
;
}
.main-background
.p
{
margin-top
:
24px
;
}
.top-bar
{
.top-bar
{
height
:
64px
;
height
:
64px
;
background
:
#1E143A
;
background
:
#1E143A
;
...
@@ -22,7 +71,8 @@
...
@@ -22,7 +71,8 @@
}
}
body
{
body
{
margin
:
0
margin
:
0
;
height
:
100%
;
}
}
.button
{
.button
{
box-sizing
:
border-box
;
box-sizing
:
border-box
;
...
@@ -44,6 +94,60 @@
...
@@ -44,6 +94,60 @@
.buttons
{
.buttons
{
float
:
right
;
float
:
right
;
display
:
flex
;
display
:
flex
;
}
.main-buttons
{
display
:
flex
;
margin-top
:
40px
;
}
.sub-content
{
position
:
absolute
;
left
:
12.4%
;
top
:
50%
;
transform
:
translateY
(
-50%
);
}
.main-background
.button
{
margin-right
:
16px
;
margin-left
:
0
;
padding
:
8px
32px
;
font-size
:
16px
;
}
button
.dropdown-field__toggler
:after
{
content
:
'▼'
;
}
button
.dropdown-field__toggler
{
background
:
transparent
!important
;
border
:
0
;
border-bottom
:
2px
solid
#594CD7
;
width
:
366px
;
position
:
relative
;
text-align
:
left
;
padding
:
4px
;
font-size
:
14px
;
line-height
:
24px
;
cursor
:
pointer
;
}
button
.dropdown-field__toggler
:after
{
content
:
'▼'
;
position
:
absolute
;
right
:
10px
;
font-family
:
arial
;
font-size
:
10px
;
transform
:
scaleY
(
0.7
)
translateY
(
4px
);
}
.dropdown-field--opened
button
.dropdown-field__toggler
:after
{
content
:
'▲'
;
}
input
[
type
=
"text"
]
{
background
:
transparent
!important
;
border
:
0
;
line-height
:
36px
;
border-bottom
:
2px
solid
#fff
;
font-size
:
16px
;
color
:
#fff
;
outline
:
none
;
}
input
[
type
=
"text"
]
:focus
{
border-bottom
:
2px
solid
#594CD7
;
}
}
.content
{
.content
{
...
@@ -56,6 +160,18 @@
...
@@ -56,6 +160,18 @@
font-size
:
32px
;
font-size
:
32px
;
margin-bottom
:
8px
;
margin-bottom
:
8px
;
}
}
.h1
{
font-size
:
40px
;
line-height
:
64px
;
font-style
:
normal
;
font-weight
:
bold
;
}
.p
{
font-size
:
16px
;
line-height
:
32px
;
font-style
:
normal
;
font-weight
:
normal
;
}
.input
{
.input
{
border
:
none
;
border
:
none
;
padding
:
4px
8px
;
padding
:
4px
8px
;
...
@@ -96,23 +212,48 @@
...
@@ -96,23 +212,48 @@
display
:
block
;
display
:
block
;
position
:
absolute
;
position
:
absolute
;
background
:
#fff
;
background
:
#fff
;
border
:
2px
solid
#6aff00
;
border
:
2px
solid
#594CD7
;
z-index
:
1
;
padding
:
8px
0
;
margin-top
:
-2px
;
min-width
:
362px
;
}
}
.dropdown-item
{
.dropdown-item
{
padding
:
4px
12px
;
padding
:
8px
20px
;
font-size
:
14px
;
line-height
:
20px
;
/* margin-bottom: 8px; */
}
}
.dropdown-item
:hover
{
.dropdown-item
:hover
{
background
:
#6aff00
;
background
:
#594CD7
;
color
:
#fff
;
cursor
:
pointer
;
cursor
:
pointer
;
}
}
.form-field__label-text
{
.form-field__label-text
{
font-size
:
18px
;
font-size
:
24px
;
margin
:
16px
0
4px
;
font-weight
:
bold
;
margin
:
40px
0
4px
;
display
:
block
;
display
:
block
;
line-height
:
32px
;
}
}
.form-field
{
.form-field
{
margin
:
2px
0
12px
;
margin
:
2px
0
12px
;
}
}
.canvas-resizer
canvas
{
display
:
block
;
}
.canvas-resizer
{
float
:
right
;
position
:
relative
;
top
:
66px
;
}
.description.gray
{
color
:
#5C5C5C
;
}
.description
{
font-size
:
14px
;
line-height
:
24px
;
}
</style>
</style>
</head>
</head>
...
@@ -135,9 +276,15 @@
...
@@ -135,9 +276,15 @@
<div
class=
"container"
>
<div
class=
"container"
>
<video
class=
"input_video"
style=
"display: none"
></video>
<video
class=
"input_video"
style=
"display: none"
></video>
</div>
</div>
<div
id=
"content"
></div>
<script
src=
"view/Select.js"
></script>
<script
src=
"view/Input.js"
></script>
<script
src=
"view/CanvasResizer.js"
></script>
<script
src=
"view/Screen.js"
></script>
<script
src=
"view/MainScreen.js"
></script>
<script
src=
"view/CallScreen.js"
></script>
<script
src=
"app.js"
></script>
<script
src=
"app.js"
></script>
<script
src=
"./bundle/apps.js"
></script>
<script
src=
"./bundle/apps.js"
></script>
<script>
<script>
...
...
build/view/CallScreen.js
View file @
4d232112
Screen
.
Conference
=
function
()
{
var
RTC
=
function
(
parent
,
canvas
,
devname
,
id
,
remoteParent
)
{
let
callApp
;
console
.
log
(
"init callapp"
);
if
(
parent
==
null
)
{
console
.
log
(
"parent was null"
);
parent
=
document
.
body
;
}
awrtc
.
SLog
.
SetLogLevel
(
awrtc
.
SLogLevel
.
Info
);
callApp
=
new
apps
.
VideoInputApp
();
callApp
.
mUiRemoteVideoParent
=
remoteParent
;
const
media
=
new
awrtc
.
Media
();
awrtc
.
Media
.
SharedInstance
.
VideoInput
.
AddCanvasDevice
(
canvas
,
devname
,
canvas
.
width
/
2
,
canvas
.
height
/
2
,
30
);
setInterval
(()
=>
{
awrtc
.
Media
.
SharedInstance
.
VideoInput
.
UpdateFrame
(
devname
);
},
50
);
//apps.VideoInputApp.sVideoDevice = devname;
callApp
.
sVideoDevice
=
devname
;
callApp
.
setupUi
(
parent
);
this
.
callApp
=
callApp
;
callApp
.
___id
=
id
;
this
.
id
=
id
;
}
var
resultProcessor
=
function
(
canvasElement
)
{
window
.
canvasElement
=
canvasElement
;
const
segmentations
=
[
false
,
false
,
false
,
false
];
let
sPointer
=
0
;
var
w
=
720
,
h
=
405
;
var
tmpCanvas
=
D
.
h
(
'canvas'
,
{
width
:
w
,
height
:
h
}),
tmpCtx
=
tmpCanvas
.
getContext
(
'2d'
),
composedMaskCanvas
=
D
.
h
(
'canvas'
,
{
width
:
w
,
height
:
h
}),
composedMaskCtx
=
composedMaskCanvas
.
getContext
(
'2d'
),
composedData
=
composedMaskCtx
.
getImageData
(
0
,
0
,
w
,
h
),
composedDataData
=
composedData
.
data
;
const
canvasCtx
=
window
.
canvasCtx
=
canvasElement
.
getContext
(
'2d'
);
return
function
(
results
){
var
max
=
Math
.
max
;
var
image
=
results
.
segmentationMask
;
tmpCtx
.
clearRect
(
0
,
0
,
w
,
h
);
tmpCtx
.
drawImage
(
image
,
0
,
0
,
image
.
width
,
image
.
height
,
0
,
0
,
w
,
h
);
segmentations
[(
sPointer
++
)
%
4
]
=
tmpCtx
.
getImageData
(
0
,
0
,
w
,
h
).
data
;
var
pos
=
canvasElement
.
position
;
var
from
=
w
*
pos
[
0
]
/
100
,
to
=
w
*
pos
[
1
]
/
100
;
if
(
sPointer
>
3
){
var
pointer
;
for
(
var
j
=
0
;
j
<
h
;
j
++
){
pointer
=
j
*
w
*
4
+
3
;
for
(
var
i
=
0
;
i
<
w
;
i
++
){
//if( ){
composedDataData
[
pointer
]
=
composedDataData
[
pointer
-
2
]
=
i
<
from
||
i
>
to
||
segmentations
[
3
][
pointer
]
+
segmentations
[
2
][
pointer
]
+
segmentations
[
1
][
pointer
]
+
segmentations
[
0
][
pointer
]
<
120
?
255
:
0
;
pointer
+=
4
;
//}
}
}
composedMaskCtx
.
putImageData
(
composedData
,
0
,
0
);
}
canvasCtx
.
drawImage
(
results
.
image
,
0
,
0
,
canvasElement
.
width
,
canvasElement
.
height
);
canvasCtx
.
drawImage
(
composedMaskCanvas
/*results.segmentationMask*/
,
0
,
0
,
canvasElement
.
width
,
canvasElement
.
height
);
};
}
var
camera1canvas
,
camera2canvas
,
single
=
new
Store
.
Value
.
Boolean
(
true
);
var
linkHook
=
_
=>
store
.
sub
(
'conference_id'
,
function
(
val
)
{
_
(
document
.
location
.
origin
+
document
.
location
.
pathname
+
'#/'
+
val
)
}),
link
=
D
.
h
(
'a'
,
{
href
:
linkHook
},
linkHook
);
var
streams
=
{};
var
userID
=
0
;
var
remoteVideoEl
=
D
.
div
({
cls
:
'remote-video'
});
var
generateUserUI
=
function
()
{
var
currentUserID
=
userID
;
var
camTypes
=
store
.
get
(
'webcamtypes'
);
store
.
set
(
'webcam'
+
userID
,
camTypes
[
userID
%
camTypes
.
length
].
value
);
var
userRoles
=
store
.
get
(
'userRoles'
);
store
.
set
(
'userRole'
+
userID
,
userRoles
[
userID
%
userRoles
.
length
].
value
);
var
cameraCanvas
,
canvasResizerEl
,
dom
=
D
.
div
({
cls
:
'block'
,
style
:
{
marginBottom
:
'80px'
}},
D
.
div
({
cls
:
'header'
},
'User '
+
(
currentUserID
+
1
)),
canvasResizerEl
=
CanvasResizer
(
cameraCanvas
=
D
.
h
(
'canvas'
,
{
cls
:
"output_canvas"
,
width
:
"640px"
,
height
:
"480px"
,
style
:
{
/*display: 'none',*/
width
:
'320px'
}
})
),
Select
({
values
:
'userRoles'
,
bind
:
store
.
bind
(
'userRole'
+
userID
),
label
:
'Your role'
}),
Select
({
values
:
'videoinput'
,
bind
:
store
.
bind
(
'videoinput'
+
userID
),
label
:
'Camera device'
}),
Select
({
values
:
'webcamtypes'
,
bind
:
store
.
bind
(
'webcam'
+
userID
),
label
:
'Camera position'
})
);
var
video1
=
D
.
h
(
'video'
);
var
cameraCanvasCtx
=
cameraCanvas
.
getContext
(
'2d'
);
var
updateVideos
=
function
()
{
cameraCanvasCtx
.
drawImage
(
video1
,
0
,
0
);
requestAnimationFrame
(
updateVideos
);
};
requestAnimationFrame
(
updateVideos
);
store
.
sub
([
'inputsSetted'
],
(
is
)
=>
{
/*store.set('videoinput1', devices.videoinput[devices.videoinput.length - 1].value);
store.set('videoinput2', devices.videoinput[Math.max(0,devices.videoinput.length - 2)].value);
store.set('videoinput3', devices.videoinput[Math.max(0,devices.videoinput.length - 3)].value);
*/
if
(
!
is
)
return
;
var
count
=
devices
.
videoinput
.
length
;
store
.
set
(
'videoinput'
+
currentUserID
,
devices
.
videoinput
[
(
count
-
1
-
currentUserID
+
count
*
currentUserID
)
%
count
].
value
);
});
store
.
sub
([
'inputsSetted'
,
'videoinput'
+
userID
],
async
(
is
,
input
)
=>
{
if
(
!
is
)
return
;
if
(
input
){
try
{
if
(
input
in
streams
){
stream
=
streams
[
input
];
}
else
{
var
stream
=
await
navigator
.
mediaDevices
.
getUserMedia
(
{
video
:
{
deviceId
:
{
exact
:
input
}
}
}
);
}
streams
[
input
]
=
stream
;
var
video
=
video1
;
video
.
srcObject
=
stream
;
video
.
play
();
canvasResizerEl
.
style
.
display
=
'block'
;
}
catch
(
e
){
canvasResizerEl
.
style
.
display
=
'none'
;
console
.
error
(
e
)
}
}
for
(
var
streamID
in
streams
){
var
inUse
=
false
;
for
(
var
j
=
0
;
j
<=
userID
;
j
++
){
if
(
store
.
get
(
'videoinput'
+
j
)
===
streamID
){
inUse
=
true
;
break
;
}
}
if
(
!
inUse
){
var
stream
=
streams
[
streamID
];
stream
.
getTracks
().
forEach
(
function
(
track
)
{
track
.
stop
();
});
}
}
});
var
RTCinstance
;
store
.
sub
(
'appLoaded'
,
function
(
loaded
)
{
if
(
!
loaded
)
return
;
RTCinstance
=
new
RTC
(
currentUserID
?
null
:
document
.
querySelector
(
"#videoinputapp1"
),
cameraCanvas
,
'canvas'
+
currentUserID
,
currentUserID
,
currentUserID
?
null
:
remoteVideoEl
);
RTCinstance
.
mUiRemoteVideoParent
=
currentUserID
?
null
:
remoteVideoEl
;
var
selfieSegmentation
=
new
SelfieSegmentation
(
{
locateFile
:
(
file
)
=>
{
return
`https://cdn.jsdelivr.net/npm/@mediapipe/selfie_segmentation/
${
file
}
`
;
}
}
);
selfieSegmentation
.
setOptions
(
{
modelSelection
:
1
,
}
);
var
resultProcessorFn
=
resultProcessor
(
cameraCanvas
)
selfieSegmentation
.
onResults
(
function
(){
resultProcessorFn
.
apply
(
this
,
arguments
)
}
);
var
segmentation
=
async
function
()
{
if
(
video1
.
videoWidth
>
10
&&
store
.
get
(
'videoinput'
+
currentUserID
)){
await
selfieSegmentation
.
send
(
{
image
:
video1
}
);
}
requestAnimationFrame
(
segmentation
);
};
requestAnimationFrame
(
segmentation
);
});
userID
++
;
return
dom
;
}
var
usersBlock
;
var
dom
=
D
.
div
({
cls
:
'top-bar'
},
D
.
h
(
'img'
,
{
src
:
'amazon-logo.svg'
}),
D
.
div
({
cls
:
'buttons'
},
D
.
h
(
'button'
,
{
cls
:
[
'button secondary'
,
{
hidden
:
Store
.
NOT
(
isConnected
)}],
onclick
:
()
=>
store
.
set
(
'connection'
,
false
)},
'End session'
),
D
.
h
(
'button'
,
{
cls
:
[
'button primary'
,
{
hidden
:
isConnected
}],
onclick
:
()
=>
store
.
set
(
'connection'
,
true
)},
'Ready to connect'
)
),
content
=
D
.
div
({
cls
:
'content'
},
D
.
div
({
cls
:
'block'
},
D
.
div
({
cls
:
'description gray'
},
'You are the host of this session'
),
D
.
div
({
cls
:
'description'
},
'Session ID: '
,
store
.
val
(
'conference_id'
)),
D
.
div
({
cls
:
'description'
},
'Link to session: '
,
link
),
),
usersBlock
=
D
.
div
({
cls
:
'users-block'
},
generateUserUI
()
),
D
.
h
(
'button'
,
{
cls
:
[
'button primary'
,
{
hidden
:
isConnected
}],
onclick
:
()
=>
usersBlock
.
appendChild
(
generateUserUI
())
},
'Add user'
),
D
.
div
({
cls
:
'block hidden'
},
D
.
div
({
cls
:
'header'
},
'Conference info'
),
LabeledInput
({
label
:
'Session ID'
,
cls
:
'callapp_address input'
,
autocomplete
:
'off'
,
value
:
'LUCID-4'
},
'conference_id'
),
),
D
.
div
({
cls
:
[
'block'
,
{
hidden
:
true
}]},
//Store.NOT(isConnected)
D
.
div
({
cls
:
[
'header'
]},
'Remote video'
),
remoteVideoEl
)
)
);
var
devices
=
{
audioinput
:
[],
audiooutput
:
[],
videoinput
:
[]};
function
gotDevices
(
deviceInfos
)
{
// Handles being called several times to update labels. Preserve values.
for
(
let
i
=
0
;
i
!==
deviceInfos
.
length
;
++
i
)
{
const
deviceInfo
=
deviceInfos
[
i
];
const
option
=
{
value
:
deviceInfo
.
deviceId
};
if
(
!
(
deviceInfo
.
kind
in
devices
)){
devices
[
deviceInfo
.
kind
]
=
[];
}
devices
[
deviceInfo
.
kind
].
push
(
option
);
var
count
=
devices
[
deviceInfo
.
kind
].
length
;
if
(
deviceInfo
.
kind
===
'audioinput'
)
{
option
.
text
=
deviceInfo
.
label
||
`microphone
${
count
}
`
;
}
else
if
(
deviceInfo
.
kind
===
'audiooutput'
)
{
option
.
text
=
deviceInfo
.
label
||
`speaker
${
count
}
`
;
}
else
if
(
deviceInfo
.
kind
===
'videoinput'
)
{
option
.
text
=
deviceInfo
.
label
||
`camera
${
count
}
`
;
}
else
{
console
.
log
(
'Some other kind of source/device: '
,
deviceInfo
);
}
}
store
.
set
(
'videoinput'
,
devices
.
videoinput
);
store
.
set
(
'audioinput'
,
devices
.
audioinput
);
store
.
set
(
'inputsSetted'
,
true
);
console
.
log
(
devices
);
/*const values = selectors.map(select => select.value);
selectors.forEach(select => {
while (select.firstChild) {
select.removeChild(select.firstChild);
}
});
for (let i = 0; i !== deviceInfos.length; ++i) {
const deviceInfo = deviceInfos[i];
const option = document.createElement('option');
option.value = deviceInfo.deviceId;
if (deviceInfo.kind === 'audioinput') {
option.text = deviceInfo.label || `microphone ${audioInputSelect.length + 1}`;
audioInputSelect.appendChild(option);
} else if (deviceInfo.kind === 'audiooutput') {
option.text = deviceInfo.label || `speaker ${audioOutputSelect.length + 1}`;
audioOutputSelect.appendChild(option);
} else if (deviceInfo.kind === 'videoinput') {
option.text = deviceInfo.label || `camera ${videoSelect.length + 1}`;
videoSelect.appendChild(option);
} else {
console.log('Some other kind of source/device: ', deviceInfo);
continue;
}
}
selectors.forEach((select, selectorIndex) => {
if (Array.prototype.slice.call(select.childNodes).some(n => n.value === values[selectorIndex])) {
select.value = values[selectorIndex];
}
});*/
}
var
handleError
=
function
(
e
)
{
console
.
log
(
'Error'
,
e
)
}
//gotDevices([{"deviceId":"default","kind":"audioinput","label":"Default - Microphone (2- Razer Kiyo) (1532:0e03)","groupId":"c9b2965558c8600ceaa11c06017152dc99f8721fef0585ad9432838b46f8f9f7"},{"deviceId":"communications","kind":"audioinput","label":"Communications - Microphone (2- Razer Kiyo) (1532:0e03)","groupId":"c9b2965558c8600ceaa11c06017152dc99f8721fef0585ad9432838b46f8f9f7"},{"deviceId":"1517d03bc4bc8e08292b02b454b79e3a93f39fa14d7c589c47c80d093093ed1e","kind":"audioinput","label":"Microphone (Steam Streaming Microphone)","groupId":"20a28b389c696bd36556474101f44876ee56f686b3717913354b85fa804c8c7a"},{"deviceId":"b963d76466dcc0490a58d9624e987a3e69d689c2529adf66f39efae8fccd031c","kind":"audioinput","label":"Microphone (Razer Kiyo) (1532:0e03)","groupId":"ea58a01565e810e30b4d7873050388edb9dc43a11007253ecc9dabd4201230fd"},{"deviceId":"3a664d8417e7000b78f8619667da3e38280269edb222a74d1375786e9c8e70d3","kind":"audioinput","label":"Mic in at rear panel (Pink) (Realtek(R) Audio)","groupId":"8e1aab63dd80f414dce561f4e368bb484c065834f3941db045ca722f61d254a4"},{"deviceId":"46ac5b427bdd38a095664fe7e817a5e7fb7cd2a7077558e72112ade79f27f3a5","kind":"audioinput","label":"Microphone (2- Razer Kiyo) (1532:0e03)","groupId":"c9b2965558c8600ceaa11c06017152dc99f8721fef0585ad9432838b46f8f9f7"},{"deviceId":"78f07683774a206866fdb098d8cac2cb5afc980ba3e670f85393eb16d5e914b9","kind":"audioinput","label":"Headset Microphone (Oculus Virtual Audio Device)","groupId":"05a90cf47adb203e6eb67353f82529c636dc92833ed13f011042a32a370c44c7"},{"deviceId":"68cb94c20ca0b8f17bbaad703c76cbce402793b5e18ddc89e68f38865ed82478","kind":"videoinput","label":"Intel(R) RealSense(TM) 435 with RGB Module Depth (8086:0b07)","groupId":"eb53f0590ee544f7848664d5e2ac6c8430659c4a34e26edf401b57fd9a8ce83c"},{"deviceId":"943c211869cd4e58039d142e22b98ca0cc53dc4d7f60723c832cf73b52b49d6f","kind":"videoinput","label":"Intel(R) RealSense(TM) 435 with RGB Module RGB (8086:0b07)","groupId":"16dd5ec91babf1e3d461bb5afe04bd4713b0c95d3c538ea6f3515dc5c3aacb9a"},{"deviceId":"0329d90dd74edc8657af0bb0d32652989fb1c162d0c294794cbc7fd76e4cf9a9","kind":"videoinput","label":"USB Video Device (1532:0e03)","groupId":"a5fe4973e22ce5b529b8cccd14ce14ed356709d356c94228cb5c2e77d804f297"},{"deviceId":"426bd00749eecdb8ce1da28ecae7d99e78310cc57aedbdf947e9288f4660ad12","kind":"videoinput","label":"USB Video Device (1532:0e03)","groupId":"1b4fc078561da2a5b19c21531d27485fa6f19368d8440d2740d94809c3b5da84"},{"deviceId":"default","kind":"audiooutput","label":"Default - Speakers (Realtek(R) Audio)","groupId":"8e1aab63dd80f414dce561f4e368bb484c065834f3941db045ca722f61d254a4"},{"deviceId":"communications","kind":"audiooutput","label":"Communications - Headphones (Oculus Virtual Audio Device)","groupId":"05a90cf47adb203e6eb67353f82529c636dc92833ed13f011042a32a370c44c7"},{"deviceId":"7c5103d23dc4e21fb0c436dbf039909bc2c70611a92587da582edd74bbee8460","kind":"audiooutput","label":"PHL BDM3490 (NVIDIA High Definition Audio)","groupId":"731a927b663a4a209a3359d16c1c1f214ded54c07f084f659ff4809e6cf588d5"},{"deviceId":"218fa70f234dbf497b6044345c531d15120f56a49e872e3062a0d9da11f8d158","kind":"audiooutput","label":"Speakers (Steam Streaming Microphone)","groupId":"20a28b389c696bd36556474101f44876ee56f686b3717913354b85fa804c8c7a"},{"deviceId":"11c4193f457b6e9cfa44f88fa6742d8a151ce7dfd8bd71b8fd97d0f5b664a6ec","kind":"audiooutput","label":"DELL U2715H (NVIDIA High Definition Audio)","groupId":"4cd1fd9ed5fe4bb80fe7984a3c60e472548f37e157239e4d901ffe8394af5205"},{"deviceId":"f9893c7a1ce8fd1f229a37d8963f9db9504c03cff47e173bc4f1ab4ee20696db","kind":"audiooutput","label":"Headphones (Oculus Virtual Audio Device)","groupId":"05a90cf47adb203e6eb67353f82529c636dc92833ed13f011042a32a370c44c7"},{"deviceId":"c611d06286b441cb1e3440e9bf09f534d98b4ed2e41528eb9c54cb7e41779c63","kind":"audiooutput","label":"Speakers (Steam Streaming Speakers)","groupId":"4d0e12aa90d61a5867f01beea961e77cb03796fd77a2c8cde7f25ec82b718ee9"},{"deviceId":"e00a5fe0a89b8c5bd2858060265e9b0937249601678974e5f3180f797e99ef9e","kind":"audiooutput","label":"Speakers (Realtek(R) Audio)","groupId":"8e1aab63dd80f414dce561f4e368bb484c065834f3941db045ca722f61d254a4"},{"deviceId":"e29c7603a6e3b56aaf3ffc5535f563dd2bce09ce208722837aecee06eaf358d9","kind":"audiooutput","label":"Realtek Digital Output (Realtek(R) Audio)","groupId":"7ae806bf56274db2fab2c6c03a14eed45022de19176702d33821bb7c8e436e8d"}])
;(
async
function
()
{
try
{
var
permissionObj
=
await
navigator
.
permissions
.
query
(
{
name
:
'microphone'
}
)
console
.
log
(
permissionObj
.
state
);
}
catch
(
error
){
console
.
log
(
'Got error :'
,
error
);
}
try
{
var
permissionObj
=
await
navigator
.
permissions
.
query
(
{
name
:
'camera'
}
)
console
.
log
(
permissionObj
.
state
);
}
catch
(
error
){
console
.
log
(
'Got error :'
,
error
);
}
navigator
.
mediaDevices
.
enumerateDevices
().
then
(
gotDevices
).
catch
(
handleError
);
setInterval
(
function
()
{
D
(
'video'
).
map
(
a
=>
a
.
muted
=
true
)
},
2000
);
})();
return
dom
;
};
\ No newline at end of file
build/view/CanvasResizer.js
View file @
4d232112
AddCss
(
'/view/canvasResizer.css'
);
const
resizeMinGap
=
20
;
//%
var
CanvasResizer
=
function
(
canvas
)
{
var
leftMover
=
D
.
div
({
cls
:
'canvas-resizer--mover canvas-resizer--mover-left'
});
var
rightMover
=
D
.
div
({
cls
:
'canvas-resizer--mover canvas-resizer--mover-right'
});
var
els
=
[
leftMover
,
rightMover
];
var
position
=
[
0
,
100
];
canvas
.
addEventListener
(
'mousedown'
,
function
(
e
)
{
var
percent
=
e
.
offsetX
/
e
.
currentTarget
.
clientWidth
*
100
,
moving
;
if
(
percent
<
position
[
0
]){
moving
=
0
;
}
else
if
(
percent
>
position
[
1
]){
moving
=
1
;
}
else
{
moving
=
Math
.
abs
(
position
[
0
]
-
percent
)
<
Math
.
abs
(
position
[
1
]
-
percent
)
?
0
:
1
;
}
var
rect
=
D
.
getRect
(
canvas
);
var
move
=
function
(
e
)
{
var
percent
=
((
e
.
clientX
-
rect
.
left
)
/
(
rect
.
width
)
*
100
);
percent
=
Math
.
min
(
percent
,
100
);
percent
=
Math
.
max
(
percent
,
0
);
if
(
moving
===
0
){
percent
=
Math
.
min
(
position
[
1
]
-
resizeMinGap
,
percent
);
}
if
(
moving
===
1
){
percent
=
Math
.
max
(
position
[
0
]
+
resizeMinGap
,
percent
);
}
position
[
moving
]
=
((
percent
*
10
)
|
0
)
/
10
;
els
[
0
].
style
.
width
=
position
[
0
]
+
'%'
;
els
[
1
].
style
.
width
=
(
100
-
position
[
1
])
+
'%'
;
e
.
preventDefault
();
e
.
stopPropagation
();
};
var
up
=
function
(
e
)
{
document
.
removeEventListener
(
'mousemove'
,
move
);
document
.
removeEventListener
(
'mouseup'
,
up
);
e
.
preventDefault
();
e
.
stopPropagation
();
}
document
.
addEventListener
(
'mousemove'
,
move
);
document
.
addEventListener
(
'mouseup'
,
up
);
});
var
dom
=
D
.
div
({
cls
:
'canvas-resizer'
},
canvas
,
leftMover
,
rightMover
);
canvas
.
position
=
position
;
return
dom
;
}
\ No newline at end of file
build/view/Input.js
View file @
4d232112
const
AddCss
=
function
(
href
)
{
D
.
h
(
'link'
,
{
href
,
rel
:
'stylesheet'
,
renderTo
:
document
.
head
})
};
const
Input
=
function
(
cfg
,
bind
)
{
cfg
.
type
=
'text'
;
cfg
.
onkeyup
=
cfg
.
oninput
=
cfg
.
onchange
=
function
()
{
store
.
set
(
bind
,
input
.
value
);
};
const
input
=
D
.
h
(
'input'
,
cfg
);
store
.
sub
(
bind
,
function
(
val
)
{
input
.
value
=
val
;
});
return
input
;
};
const
LabeledInput
=
function
(
cfg
,
bind
)
{
return
D
.
h
(
'label'
,
{},
D
.
div
.
apply
(
D
,
[{
cls
:
'label_label'
}].
concat
(
cfg
.
label
)),
Input
(
cfg
,
bind
)
)
}
\ No newline at end of file
build/view/MainScreen.js
View file @
4d232112
Screen
.
Main
=
function
()
{
const
showJoinForm
=
new
Store
.
Value
.
Boolean
(
false
);
const
dom
=
D
.
div
({
cls
:
'main-background'
},
D
.
h
(
'img'
,
{
src
:
'amazon-logo.svg'
,
cls
:
'logo'
}),
D
.
div
({
cls
:
'sub-content'
},
D
.
div
({
cls
:
[
'main-connection-type-select'
,
{
hidden
:
showJoinForm
}]},
D
.
div
({
cls
:
'h1'
},
'Conferences made easy'
),
D
.
div
({
cls
:
'p'
},
'Use VR calls with remote guests to immerse in conversation and'
,
D
.
h
(
'br'
),
'feel more involved'
),
D
.
div
({
cls
:
'main-buttons'
},
D
.
h
(
'button'
,
{
cls
:
'button primary'
,
onclick
:
()
=>
Screen
.
show
(
'Conference'
)},
'Create New Session'
),
D
.
h
(
'button'
,
{
cls
:
'button primary'
,
onclick
:
()
=>
showJoinForm
.
set
(
true
)},
'Connect to Session'
),
)
),
D
.
div
({
cls
:
[
'join-screen'
,
{
hidden
:
Store
.
NOT
(
showJoinForm
)}]},
D
.
div
({
cls
:
'h1'
},
'Enter Session ID'
),
D
.
div
({
cls
:
'p'
},
Input
({
placeholder
:
'Session ID'
},
'conference_id'
)
),
D
.
div
({
cls
:
'main-buttons'
},
D
.
h
(
'button'
,
{
cls
:
'button primary'
,
onclick
:
()
=>
Screen
.
show
(
'Conference'
)},
'Connect to Session'
),
D
.
h
(
'button'
,
{
cls
:
'button secondary'
,
onclick
:
()
=>
showJoinForm
.
set
(
false
)},
'Go Back'
),
)
)
)
);
return
dom
;
};
\ No newline at end of file
build/view/Screen.js
View file @
4d232112
const
Screen
=
{
cache
:
{},
show
:
function
(
name
)
{
const
renderEl
=
document
.
getElementById
(
'content'
);
D
.
removeChildren
(
renderEl
);
if
(
!
(
name
in
Screen
.
cache
)){
Screen
.
cache
[
name
]
=
Screen
[
name
]();
}
renderEl
.
appendChild
(
Screen
.
cache
[
name
]);
}
};
\ No newline at end of file
build/view/Select.js
View file @
4d232112
var
Select
=
function
(
cfg
)
{
let
isOpen
=
this
.
isOpen
=
new
Store
.
Value
.
Boolean
(
false
);
var
table
=
D
.
div
({
cls
:
'dropdown-list'
},
_
=>
{
store
.
sub
(
cfg
.
values
,
function
(
val
)
{
if
(
val
){
_
(
val
.
map
(
function
(
v
)
{
return
D
.
div
({
cls
:
'dropdown-item'
,
'data-id'
:
v
.
value
,
onclick
:
function
()
{
cfg
.
bind
.
set
(
v
.
value
);
isOpen
.
set
(
false
);
}},
v
.
text
)
}));
}
});
});
var
dom
=
D
.
div
({
cls
:
'form-field'
},
D
.
div
({
cls
:
'form-field__label'
},
D
.
span
({
cls
:
'form-field__label-text'
},
cfg
.
label
),
D
.
div
({
cls
:
[
'dropdown-field'
,
{
'dropdown-field--opened'
:
isOpen
}]},
D
.
h
(
'button'
,
{
cls
:
'dropdown-field__toggler'
,
onclick
:
()
=>
isOpen
.
toggle
()
},
D
.
span
({
cls
:
D
.
cls
(
"dropdown-field__placeholder"
,
{
"dropdown-field__placeholder--filled"
:
_
=>
cfg
.
bind
.
sub
(
val
=>
_
(
!!
(
cfg
.
multivalue
?
val
&&
val
.
length
:
val
&&
val
.
name
)))
}
)},
_
=>
{
cfg
.
bind
.
sub
(
val
=>
{
if
(
val
){
var
vals
=
store
.
get
(
cfg
.
values
)
||
[],
theVal
=
vals
.
filter
(
v
=>
v
.
value
===
val
)[
0
];
_
(
theVal
?
theVal
.
text
:
'Select'
)
}
else
{
_
(
cfg
.
placeholder
);
}
}
);
}
)
),
D
.
div
({
cls
:
'dropdown-field__tooltip'
},
table
)
)
)
);
return
dom
;
}
\ No newline at end of file
build/view/canvasResizer.css
View file @
4d232112
.canvas-resizer--mover
{
position
:
absolute
;
top
:
0
;
bottom
:
0
;
background
:
rgba
(
0
,
0
,
0
,
0.5
);
cursor
:
ew-resize
;
pointer-events
:
none
;
}
.canvas-resizer
{
display
:
none
;
}
.canvas-resizer
canvas
{
cursor
:
ew-resize
;
}
.canvas-resizer--mover-left
{
left
:
0
;
width
:
0px
;
border-right
:
2px
solid
#594CD7
;
}
.canvas-resizer--mover-right
{
right
:
0
;
width
:
0px
;
border-left
:
2px
solid
#594CD7
;
}
\ No newline at end of file
src/apps/videoinputapp.ts
View file @
4d232112
...
@@ -299,11 +299,15 @@ export class VideoInputApp {
...
@@ -299,11 +299,15 @@ export class VideoInputApp {
}
}
private
Ui_OnCleanup
()
{
private
Ui_OnCleanup
()
{
store
.
set
(
'connection'
,
false
);
store
.
set
(
'connection'
,
false
);
while
(
this
.
mUiLocalVideoParent
.
hasChildNodes
())
{
while
(
this
.
mUiLocalVideoParent
.
hasChildNodes
())
{
this
.
mUiLocalVideoParent
.
removeChild
(
this
.
mUiLocalVideoParent
.
firstChild
);
this
.
mUiLocalVideoParent
.
removeChild
(
this
.
mUiLocalVideoParent
.
firstChild
);
}
}
while
(
window
[
'remoteVideoEl'
].
hasChildNodes
())
{
window
[
'remoteVideoEl'
].
removeChild
(
window
[
'remoteVideoEl'
].
firstChild
);
if
(
this
.
mUiRemoteVideoParent
)
{
while
(
this
.
mUiRemoteVideoParent
.
hasChildNodes
())
{
this
.
mUiRemoteVideoParent
.
removeChild
(
this
.
mUiRemoteVideoParent
.
firstChild
);
}
}
}
}
}
private
Ui_OnLog
(
msg
:
string
)
{
private
Ui_OnLog
(
msg
:
string
)
{
...
@@ -320,12 +324,14 @@ export class VideoInputApp {
...
@@ -320,12 +324,14 @@ export class VideoInputApp {
private
Ui_OnRemoteVideo
(
video
:
HTMLVideoElement
,
id
:
awrtc
.
ConnectionId
)
{
private
Ui_OnRemoteVideo
(
video
:
HTMLVideoElement
,
id
:
awrtc
.
ConnectionId
)
{
const
D
=
window
[
'D'
];
const
D
=
window
[
'D'
];
video
.
muted
=
true
;
video
.
muted
=
true
;
window
[
'remoteVideoEl'
].
appendChild
(
if
(
this
.
mUiRemoteVideoParent
){
D
.
div
({
cls
:
'income-video'
},
this
.
mUiRemoteVideoParent
.
appendChild
(
D
.
div
({
cls
:
'income-video-id'
},
'stream '
+
id
.
id
),
D
.
div
({
cls
:
'income-video'
},
video
D
.
div
({
cls
:
'income-video-id'
},
'stream '
+
id
.
id
),
)
video
);
)
);
}
}
}
public
Ui_OnStartStopButtonClicked
=
()
=>
{
public
Ui_OnStartStopButtonClicked
=
()
=>
{
...
@@ -360,6 +366,7 @@ export class VideoInputApp {
...
@@ -360,6 +366,7 @@ export class VideoInputApp {
private
GenerateRandomKey
()
{
private
GenerateRandomKey
()
{
var
result
=
"LUCID-"
+
(
Math
.
random
()
*
10
|
0
);
var
result
=
"LUCID-"
+
(
Math
.
random
()
*
10
|
0
);
result
=
store
.
get
(
'conference_id'
);
/*for (var i = 0; i < 7; i++) {
/*for (var i = 0; i < 7; i++) {
result += String.fromCharCode(65 + Math.round(Math.random() * 25));
result += String.fromCharCode(65 + Math.round(Math.random() * 25));
}*/
}*/
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment