Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
galene
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
galene
Commits
cbff5067
Commit
cbff5067
authored
May 21, 2020
by
Juliusz Chroboczek
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement sharing of multiple application windows at a time.
parent
9fde0299
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
157 additions
and
119 deletions
+157
-119
static/sfu.css
static/sfu.css
+16
-5
static/sfu.html
static/sfu.html
+17
-15
static/sfu.js
static/sfu.js
+124
-99
No files found.
static/sfu.css
View file @
cbff5067
...
@@ -32,11 +32,7 @@ h1 {
...
@@ -32,11 +32,7 @@ h1 {
display
:
inline
display
:
inline
}
}
.userform-invisible
{
.invisible
{
display
:
none
;
}
.disconnect-invisible
{
display
:
none
;
display
:
none
;
}
}
...
@@ -53,6 +49,12 @@ h1 {
...
@@ -53,6 +49,12 @@ h1 {
margin-bottom
:
4px
;
margin-bottom
:
4px
;
}
}
#presentbutton
,
#unpresentbutton
{
width
:
8em
;
white-space
:
nowrap
;
margin-right
:
0.4em
;
}
#videoselect
{
#videoselect
{
width
:
8em
;
width
:
8em
;
text-align-last
:
center
;
text-align-last
:
center
;
...
@@ -65,6 +67,15 @@ h1 {
...
@@ -65,6 +67,15 @@ h1 {
margin-right
:
0.4em
;
margin-right
:
0.4em
;
}
}
#sharebutton
,
#unsharebutton
{
width
:
8em
;
white-space
:
nowrap
;
}
#unsharebutton
{
margin-right
:
0.4em
;
}
#requestselect
{
#requestselect
{
width
:
8em
;
width
:
8em
;
text-align-last
:
center
;
text-align-last
:
center
;
...
...
static/sfu.html
View file @
cbff5067
...
@@ -23,15 +23,16 @@
...
@@ -23,15 +23,16 @@
autocomplete=
"current-password"
/>
autocomplete=
"current-password"
/>
<input
id=
"connectbutton"
type=
"submit"
value=
"Connect"
disabled
/>
<input
id=
"connectbutton"
type=
"submit"
value=
"Connect"
disabled
/>
</form>
</form>
<input
id=
"disconnectbutton"
class=
"
disconnect-
invisible"
<input
id=
"disconnectbutton"
class=
"invisible"
type=
"submit"
value=
"Disconnect"
/>
type=
"submit"
value=
"Disconnect"
/>
<span
id=
"errspan"
></span>
<span
id=
"errspan"
></span>
</div>
</div>
<div
id=
"optionsdiv"
>
<div
id=
"optionsdiv"
>
<
label
for=
"presenterbox"
>
Present:
</label
>
<
button
id=
"presentbutton"
class=
"invisible"
>
Present
</button
>
<
input
id=
"presenterbox"
type=
"checkbox"
disabled
/
>
<
button
id=
"unpresentbutton"
class=
"invisible"
>
Stop presenting
</button
>
<span
id=
"mediaoptions"
>
<label
for=
"videoselect"
>
Camera:
</label>
<label
for=
"videoselect"
>
Camera:
</label>
<select
id=
"videoselect"
>
<select
id=
"videoselect"
>
<option>
default
</option>
<option>
default
</option>
...
@@ -43,9 +44,10 @@
...
@@ -43,9 +44,10 @@
<option>
default
</option>
<option>
default
</option>
<option>
off
</option>
<option>
off
</option>
</select>
</select>
</span>
<
label
for=
"sharebox"
>
Share screen:
</label
>
<
button
id=
"sharebutton"
class=
"invisible"
>
Share screen
</button
>
<
input
id=
"sharebox"
type=
"checkbox"
disabled
/
>
<
button
id=
"unsharebutton"
class=
"invisible"
>
Stop sharing
</button
>
<label
for=
"requestselect"
>
Receive:
</label>
<label
for=
"requestselect"
>
Receive:
</label>
<select
id=
"requestselect"
>
<select
id=
"requestselect"
>
...
...
static/sfu.js
View file @
cbff5067
...
@@ -36,6 +36,7 @@ function randomid() {
...
@@ -36,6 +36,7 @@ function randomid() {
function
Connection
(
id
,
pc
)
{
function
Connection
(
id
,
pc
)
{
this
.
id
=
id
;
this
.
id
=
id
;
this
.
kind
=
null
;
this
.
label
=
null
;
this
.
label
=
null
;
this
.
pc
=
pc
;
this
.
pc
=
pc
;
this
.
stream
=
null
;
this
.
stream
=
null
;
...
@@ -100,9 +101,9 @@ function setConnected(connected) {
...
@@ -100,9 +101,9 @@ function setConnected(connected) {
statspan
.
textContent
=
'
Connected
'
;
statspan
.
textContent
=
'
Connected
'
;
statspan
.
classList
.
remove
(
'
disconnected
'
);
statspan
.
classList
.
remove
(
'
disconnected
'
);
statspan
.
classList
.
add
(
'
connected
'
);
statspan
.
classList
.
add
(
'
connected
'
);
userform
.
classList
.
add
(
'
userform-
invisible
'
);
userform
.
classList
.
add
(
'
invisible
'
);
userform
.
classList
.
remove
(
'
userform
'
);
userform
.
classList
.
remove
(
'
userform
'
);
disconnectbutton
.
classList
.
remove
(
'
disconnect-
invisible
'
);
disconnectbutton
.
classList
.
remove
(
'
invisible
'
);
displayUsername
();
displayUsername
();
}
else
{
}
else
{
let
userpass
=
getUserPass
();
let
userpass
=
getUserPass
();
...
@@ -114,33 +115,75 @@ function setConnected(connected) {
...
@@ -114,33 +115,75 @@ function setConnected(connected) {
statspan
.
classList
.
remove
(
'
connected
'
);
statspan
.
classList
.
remove
(
'
connected
'
);
statspan
.
classList
.
add
(
'
disconnected
'
);
statspan
.
classList
.
add
(
'
disconnected
'
);
userform
.
classList
.
add
(
'
userform
'
);
userform
.
classList
.
add
(
'
userform
'
);
userform
.
classList
.
remove
(
'
userform-
invisible
'
);
userform
.
classList
.
remove
(
'
invisible
'
);
disconnectbutton
.
classList
.
add
(
'
disconnect-
invisible
'
);
disconnectbutton
.
classList
.
add
(
'
invisible
'
);
permissions
=
{};
permissions
=
{};
clearUsername
(
false
);
clearUsername
(
false
);
}
}
}
}
document
.
getElementById
(
'
present
erbox
'
).
onchange
=
function
(
e
)
{
document
.
getElementById
(
'
present
button
'
).
onclick
=
function
(
e
)
{
e
.
preventDefault
();
e
.
preventDefault
();
setLocalMedia
(
this
.
checked
);
addLocalMedia
(
);
};
};
document
.
getElementById
(
'
unpresentbutton
'
).
onclick
=
function
(
e
)
{
e
.
preventDefault
();
delUpMediaKind
(
'
local
'
);
};
function
changePresentation
()
{
let
found
=
false
;
for
(
let
id
in
up
)
{
if
(
up
[
id
].
kind
===
'
local
'
)
found
=
true
;
}
delUpMediaKind
(
'
local
'
);
if
(
found
)
addLocalMedia
();
}
function
setVisibility
(
id
,
visible
)
{
let
elt
=
document
.
getElementById
(
id
);
if
(
visible
)
elt
.
classList
.
remove
(
'
invisible
'
);
else
elt
.
classList
.
add
(
'
invisible
'
);
}
function
setButtonsVisibility
()
{
let
local
=
findUpMedia
(
'
local
'
);
let
share
=
findUpMedia
(
'
screenshare
'
)
// don't allow multiple presentations
setVisibility
(
'
presentbutton
'
,
permissions
.
present
&&
!
local
);
setVisibility
(
'
unpresentbutton
'
,
local
);
// allow multiple shared documents
setVisibility
(
'
sharebutton
'
,
permissions
.
present
);
setVisibility
(
'
unsharebutton
'
,
share
);
setVisibility
(
'
mediaoptions
'
,
permissions
.
present
);
}
document
.
getElementById
(
'
audioselect
'
).
onchange
=
function
(
e
)
{
document
.
getElementById
(
'
audioselect
'
).
onchange
=
function
(
e
)
{
e
.
preventDefault
();
e
.
preventDefault
();
setLocalMedia
(
document
.
getElementById
(
'
presenterbox
'
).
checked
);
changePresentation
(
);
};
};
document
.
getElementById
(
'
videoselect
'
).
onchange
=
function
(
e
)
{
document
.
getElementById
(
'
videoselect
'
).
onchange
=
function
(
e
)
{
e
.
preventDefault
();
e
.
preventDefault
();
setLocalMedia
(
document
.
getElementById
(
'
presenterbox
'
).
checked
);
changePresentation
(
);
};
};
document
.
getElementById
(
'
shareb
ox
'
).
onchange
=
function
(
e
)
{
document
.
getElementById
(
'
shareb
utton
'
).
onclick
=
function
(
e
)
{
e
.
preventDefault
();
e
.
preventDefault
();
setShareMedia
(
this
.
checked
);
addShareMedia
(
);
};
};
document
.
getElementById
(
'
unsharebutton
'
).
onclick
=
function
(
e
)
{
e
.
preventDefault
();
delUpMediaKind
(
'
screenshare
'
);
}
document
.
getElementById
(
'
requestselect
'
).
onchange
=
function
(
e
)
{
document
.
getElementById
(
'
requestselect
'
).
onchange
=
function
(
e
)
{
e
.
preventDefault
();
e
.
preventDefault
();
sendRequest
(
this
.
value
);
sendRequest
(
this
.
value
);
...
@@ -273,26 +316,13 @@ async function setMediaChoices() {
...
@@ -273,26 +316,13 @@ async function setMediaChoices() {
mediaChoicesDone
=
true
;
mediaChoicesDone
=
true
;
}
}
let
localMediaId
=
null
;
async
function
addLocalMedia
()
{
async
function
setLocalMedia
(
setup
)
{
if
(
!
getUserPass
())
if
(
!
getUserPass
())
return
;
return
;
if
(
!
setup
)
{
if
(
localMediaId
)
{
up
[
localMediaId
].
close
(
true
);
delete
(
up
[
localMediaId
]);
delMedia
(
localMediaId
);
localMediaId
=
null
;
}
return
;
}
let
audio
=
mapMediaOption
(
document
.
getElementById
(
'
audioselect
'
).
value
);
let
audio
=
mapMediaOption
(
document
.
getElementById
(
'
audioselect
'
).
value
);
let
video
=
mapMediaOption
(
document
.
getElementById
(
'
videoselect
'
).
value
);
let
video
=
mapMediaOption
(
document
.
getElementById
(
'
videoselect
'
).
value
);
setLocalMedia
(
false
);
if
(
!
audio
&&
!
video
)
if
(
!
audio
&&
!
video
)
return
;
return
;
...
@@ -302,15 +332,14 @@ async function setLocalMedia(setup) {
...
@@ -302,15 +332,14 @@ async function setLocalMedia(setup) {
stream
=
await
navigator
.
mediaDevices
.
getUserMedia
(
constraints
);
stream
=
await
navigator
.
mediaDevices
.
getUserMedia
(
constraints
);
}
catch
(
e
)
{
}
catch
(
e
)
{
console
.
error
(
e
);
console
.
error
(
e
);
document
.
getElementById
(
'
presenterbox
'
).
checked
=
false
;
await
setLocalMedia
(
false
);
return
;
return
;
}
}
setMediaChoices
();
setMediaChoices
();
localMediaId
=
await
newUpStream
();
let
id
=
await
newUpStream
();
let
c
=
up
[
localMediaId
];
let
c
=
up
[
id
];
c
.
kind
=
'
local
'
;
c
.
stream
=
stream
;
c
.
stream
=
stream
;
stream
.
getTracks
().
forEach
(
t
=>
{
stream
.
getTracks
().
forEach
(
t
=>
{
c
.
labels
[
t
.
id
]
=
t
.
kind
c
.
labels
[
t
.
id
]
=
t
.
kind
...
@@ -320,45 +349,32 @@ async function setLocalMedia(setup) {
...
@@ -320,45 +349,32 @@ async function setLocalMedia(setup) {
},
2000
);
},
2000
);
});
});
c
.
setInterval
(()
=>
{
c
.
setInterval
(()
=>
{
displayStats
(
localMediaI
d
);
displayStats
(
i
d
);
},
2500
);
},
2500
);
await
setMedia
(
localMediaId
);
await
setMedia
(
id
);
setButtonsVisibility
()
}
}
let
shareMediaId
=
null
;
async
function
addShareMedia
(
setup
)
{
async
function
setShareMedia
(
setup
)
{
if
(
!
getUserPass
())
if
(
!
getUserPass
())
return
;
return
;
if
(
!
setup
)
{
if
(
shareMediaId
)
{
up
[
shareMediaId
].
close
(
true
);
delete
(
up
[
shareMediaId
]);
delMedia
(
shareMediaId
)
shareMediaId
=
null
;
}
return
;
}
if
(
!
shareMediaId
)
{
let
stream
=
null
;
let
stream
=
null
;
try
{
try
{
stream
=
await
navigator
.
mediaDevices
.
getDisplayMedia
({});
stream
=
await
navigator
.
mediaDevices
.
getDisplayMedia
({});
}
catch
(
e
)
{
}
catch
(
e
)
{
console
.
error
(
e
);
console
.
error
(
e
);
document
.
getElementById
(
'
sharebox
'
).
checked
=
false
;
await
setShareMedia
(
false
);
return
;
return
;
}
}
shareMediaId
=
await
newUpStream
();
let
c
=
up
[
shareMediaId
];
let
id
=
await
newUpStream
();
let
c
=
up
[
id
];
c
.
kind
=
'
screenshare
'
;
c
.
stream
=
stream
;
c
.
stream
=
stream
;
stream
.
getTracks
().
forEach
(
t
=>
{
stream
.
getTracks
().
forEach
(
t
=>
{
let
sender
=
c
.
pc
.
addTrack
(
t
,
stream
);
let
sender
=
c
.
pc
.
addTrack
(
t
,
stream
);
t
.
onended
=
e
=>
{
t
.
onended
=
e
=>
{
document
.
getElementById
(
'
sharebox
'
).
checked
=
false
;
delUpMedia
(
id
);
setShareMedia
(
false
);
};
};
c
.
labels
[
t
.
id
]
=
'
screenshare
'
;
c
.
labels
[
t
.
id
]
=
'
screenshare
'
;
c
.
setInterval
(()
=>
{
c
.
setInterval
(()
=>
{
...
@@ -366,10 +382,44 @@ async function setShareMedia(setup) {
...
@@ -366,10 +382,44 @@ async function setShareMedia(setup) {
},
2000
);
},
2000
);
});
});
c
.
setInterval
(()
=>
{
c
.
setInterval
(()
=>
{
displayStats
(
shareMediaI
d
);
displayStats
(
i
d
);
},
2500
);
},
2500
);
await
setMedia
(
shareMediaId
);
await
setMedia
(
id
);
setButtonsVisibility
()
}
function
delUpMedia
(
id
)
{
let
c
=
up
[
id
];
if
(
!
c
)
{
console
.
error
(
"
Deleting unknown up media
"
);
return
;
}
c
.
close
(
true
);
delMedia
(
id
);
delete
(
up
[
id
]);
setButtonsVisibility
()
}
function
delUpMediaKind
(
kind
)
{
for
(
let
id
in
up
)
{
let
c
=
up
[
id
];
if
(
c
.
kind
!=
kind
)
continue
c
.
close
(
true
);
delMedia
(
id
);
delete
(
up
[
id
]);
}
}
setButtonsVisibility
()
}
function
findUpMedia
(
kind
)
{
for
(
let
id
in
up
)
{
if
(
up
[
id
].
kind
===
kind
)
return
true
;
}
return
false
;
}
}
function
setMedia
(
id
)
{
function
setMedia
(
id
)
{
...
@@ -493,12 +543,8 @@ function serverConnect() {
...
@@ -493,12 +543,8 @@ function serverConnect() {
};
};
socket
.
onclose
=
function
(
e
)
{
socket
.
onclose
=
function
(
e
)
{
setConnected
(
false
);
setConnected
(
false
);
document
.
getElementById
(
'
presenterbox
'
).
checked
=
false
;
delUpMediaKind
(
'
local
'
);
document
.
getElementById
(
'
presenterbox
'
).
disabled
=
true
;
delUpMediaKind
(
'
screenshare
'
);
setLocalMedia
(
false
);
document
.
getElementById
(
'
sharebox
'
).
checked
=
false
;
document
.
getElementById
(
'
sharebox
'
).
disabled
=
true
;
setShareMedia
(
false
);
for
(
let
id
in
down
)
{
for
(
let
id
in
down
)
{
let
c
=
down
[
id
];
let
c
=
down
[
id
];
delete
(
down
[
id
]);
delete
(
down
[
id
]);
...
@@ -648,21 +694,7 @@ function gotClose(id) {
...
@@ -648,21 +694,7 @@ function gotClose(id) {
}
}
function
gotAbort
(
id
)
{
function
gotAbort
(
id
)
{
let
c
=
up
[
id
];
delUpMedia
(
id
);
if
(
!
c
)
throw
new
Error
(
'
unknown up stream in abort
'
);
if
(
id
===
localMediaId
)
{
document
.
getElementById
(
'
presenterbox
'
).
checked
=
false
;
setLocalMedia
(
false
);
}
else
if
(
id
===
shareMediaId
)
{
document
.
getElementById
(
'
sharebox
'
).
checked
=
false
;
setShareMedia
(
false
);
}
else
{
console
.
error
(
'
Strange stream in abort
'
);
delMedia
(
id
);
c
.
pc
.
close
();
delete
(
up
[
id
]);
}
}
}
async
function
gotICE
(
id
,
candidate
)
{
async
function
gotICE
(
id
,
candidate
)
{
...
@@ -753,9 +785,8 @@ function clearUsername() {
...
@@ -753,9 +785,8 @@ function clearUsername() {
function
gotPermissions
(
perm
)
{
function
gotPermissions
(
perm
)
{
permissions
=
perm
;
permissions
=
perm
;
document
.
getElementById
(
'
presenterbox
'
).
disabled
=
!
perm
.
present
;
document
.
getElementById
(
'
sharebox
'
).
disabled
=
!
perm
.
present
;
displayUsername
();
displayUsername
();
setButtonsVisibility
();
}
}
const
urlRegexp
=
/https
?
:
\/\/[
-a-zA-Z0-9@:%
/
._
\\
+~#=?
]
+
[
-a-zA-Z0-9@:%
/
_
\\
+~#=
]
/g
;
const
urlRegexp
=
/https
?
:
\/\/[
-a-zA-Z0-9@:%
/
._
\\
+~#=?
]
+
[
-a-zA-Z0-9@:%
/
_
\\
+~#=
]
/g
;
...
@@ -1088,18 +1119,12 @@ async function getIceServers() {
...
@@ -1088,18 +1119,12 @@ async function getIceServers() {
iceServers
=
servers
;
iceServers
=
servers
;
}
}
async
function
doConnect
()
{
await
serverConnect
();
await
setLocalMedia
(
document
.
getElementById
(
'
presenterbox
'
).
checked
);
await
setShareMedia
(
document
.
getElementById
(
'
sharebox
'
).
checked
);
}
document
.
getElementById
(
'
userform
'
).
onsubmit
=
async
function
(
e
)
{
document
.
getElementById
(
'
userform
'
).
onsubmit
=
async
function
(
e
)
{
e
.
preventDefault
();
e
.
preventDefault
();
let
username
=
document
.
getElementById
(
'
username
'
).
value
.
trim
();
let
username
=
document
.
getElementById
(
'
username
'
).
value
.
trim
();
let
password
=
document
.
getElementById
(
'
password
'
).
value
;
let
password
=
document
.
getElementById
(
'
password
'
).
value
;
setUserPass
(
username
,
password
);
setUserPass
(
username
,
password
);
await
do
Connect
();
await
server
Connect
();
};
};
document
.
getElementById
(
'
disconnectbutton
'
).
onclick
=
function
(
e
)
{
document
.
getElementById
(
'
disconnectbutton
'
).
onclick
=
function
(
e
)
{
...
@@ -1121,7 +1146,7 @@ function start() {
...
@@ -1121,7 +1146,7 @@ function start() {
}).
then
(
c
=>
{
}).
then
(
c
=>
{
let
userpass
=
getUserPass
();
let
userpass
=
getUserPass
();
if
(
userpass
)
if
(
userpass
)
do
Connect
();
return
server
Connect
();
});
});
}
}
...
...
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