mirror of
https://github.com/jech/galene.git
synced 2024-11-10 02:35:58 +01:00
Initial implementation of mike and camera selection.
We're closing and reopening the connection each time, we should be renegotiating instead.
This commit is contained in:
parent
175b08bb08
commit
f78030c482
3 changed files with 137 additions and 24 deletions
|
@ -49,6 +49,22 @@ h1 {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#optionsdiv {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#videoselect {
|
||||||
|
width: 8em;
|
||||||
|
text-align-last: center;
|
||||||
|
margin-right: 0.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#audioselect {
|
||||||
|
width: 8em;
|
||||||
|
text-align-last: center;
|
||||||
|
margin-right: 0.4em;
|
||||||
|
}
|
||||||
|
|
||||||
#main {
|
#main {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
@ -111,6 +127,7 @@ h1 {
|
||||||
}
|
}
|
||||||
|
|
||||||
#input {
|
#input {
|
||||||
|
margin-left: 0.5em;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: none;
|
border: none;
|
||||||
resize: none;
|
resize: none;
|
||||||
|
|
|
@ -31,8 +31,22 @@
|
||||||
<div id="optionsdiv">
|
<div id="optionsdiv">
|
||||||
<label for="presenterbox">Present:</label>
|
<label for="presenterbox">Present:</label>
|
||||||
<input id="presenterbox" type="checkbox"/ disabled>
|
<input id="presenterbox" type="checkbox"/ disabled>
|
||||||
|
|
||||||
|
<label for="videoselect">Camera:</label>
|
||||||
|
<select id="videoselect">
|
||||||
|
<option>default</option>
|
||||||
|
<option>off</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<label for="audioselect">Microphone:</label>
|
||||||
|
<select id="audioselect">
|
||||||
|
<option>default</option>
|
||||||
|
<option>off</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
<label for="sharebox">Share screen:</label>
|
<label for="sharebox">Share screen:</label>
|
||||||
<input id="sharebox" type="checkbox"/ disabled>
|
<input id="sharebox" type="checkbox"/ disabled>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
130
static/sfu.js
130
static/sfu.js
|
@ -126,6 +126,16 @@ document.getElementById('presenterbox').onchange = function(e) {
|
||||||
setLocalMedia(this.checked);
|
setLocalMedia(this.checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.getElementById('audioselect').onchange = function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
setLocalMedia(document.getElementById('presenterbox').checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('videoselect').onchange = function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
setLocalMedia(document.getElementById('presenterbox').checked);
|
||||||
|
}
|
||||||
|
|
||||||
document.getElementById('sharebox').onchange = function(e) {
|
document.getElementById('sharebox').onchange = function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setShareMedia(this.checked);
|
setShareMedia(this.checked);
|
||||||
|
@ -193,6 +203,71 @@ function displayStats(id) {
|
||||||
setLabel(id);
|
setLabel(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mapMediaOption(value) {
|
||||||
|
console.assert(typeof(value) === 'string');
|
||||||
|
switch(value) {
|
||||||
|
case 'default':
|
||||||
|
return true;
|
||||||
|
case 'off':
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addSelectOption(select, label, value) {
|
||||||
|
if(!value)
|
||||||
|
value = label;
|
||||||
|
for(let i = 0; i < select.children.length; i++) {
|
||||||
|
if(select.children[i].value === value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let option = document.createElement('option');
|
||||||
|
option.value = value;
|
||||||
|
option.textContent = label;
|
||||||
|
select.appendChild(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
// media names might not be available before we call getDisplayMedia. So
|
||||||
|
// we call this lazily.
|
||||||
|
let mediaChoicesDone = false;
|
||||||
|
|
||||||
|
async function setMediaChoices() {
|
||||||
|
if(mediaChoicesDone)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let devices = [];
|
||||||
|
try {
|
||||||
|
devices = await navigator.mediaDevices.enumerateDevices();
|
||||||
|
} catch(e) {
|
||||||
|
console.error(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cn = 1, mn = 1;
|
||||||
|
|
||||||
|
devices.forEach(d => {
|
||||||
|
let label = d.label;
|
||||||
|
if(d.kind === 'videoinput') {
|
||||||
|
if(!label)
|
||||||
|
label = `Camera ${cn}`;
|
||||||
|
addSelectOption(document.getElementById('videoselect'),
|
||||||
|
label, d.deviceId);
|
||||||
|
cn++;
|
||||||
|
} else if(d.kind === 'audioinput') {
|
||||||
|
if(!label)
|
||||||
|
label = `Microphone ${mn}`;
|
||||||
|
addSelectOption(document.getElementById('audioselect'),
|
||||||
|
label, d.deviceId);
|
||||||
|
mn++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mediaChoicesDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
let localMediaId = null;
|
let localMediaId = null;
|
||||||
|
|
||||||
async function setLocalMedia(setup) {
|
async function setLocalMedia(setup) {
|
||||||
|
@ -209,32 +284,39 @@ async function setLocalMedia(setup) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!localMediaId) {
|
let audio = mapMediaOption(document.getElementById('audioselect').value);
|
||||||
let constraints = {audio: true, video: true};
|
let video = mapMediaOption(document.getElementById('videoselect').value);
|
||||||
let stream = null;
|
|
||||||
try {
|
|
||||||
stream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
||||||
} catch(e) {
|
|
||||||
console.error(e);
|
|
||||||
document.getElementById('presenterbox').checked = false;
|
|
||||||
await setLocalMedia(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
localMediaId = await newUpStream();
|
|
||||||
|
|
||||||
let c = up[localMediaId];
|
setLocalMedia(false);
|
||||||
c.stream = stream;
|
if(!audio && !video)
|
||||||
stream.getTracks().forEach(t => {
|
return;
|
||||||
let sender = c.pc.addTrack(t, stream);
|
|
||||||
c.setInterval(() => {
|
let constraints = {audio: audio, video: video};
|
||||||
updateStats(c, sender);
|
let stream = null;
|
||||||
}, 2000);
|
try {
|
||||||
});
|
stream = await navigator.mediaDevices.getUserMedia(constraints);
|
||||||
c.setInterval(() => {
|
} catch(e) {
|
||||||
displayStats(localMediaId);
|
console.error(e);
|
||||||
}, 2500);
|
document.getElementById('presenterbox').checked = false;
|
||||||
await setMedia(localMediaId);
|
await setLocalMedia(false);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setMediaChoices();
|
||||||
|
|
||||||
|
localMediaId = await newUpStream();
|
||||||
|
let c = up[localMediaId];
|
||||||
|
c.stream = stream;
|
||||||
|
stream.getTracks().forEach(t => {
|
||||||
|
let sender = c.pc.addTrack(t, stream);
|
||||||
|
c.setInterval(() => {
|
||||||
|
updateStats(c, sender);
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
c.setInterval(() => {
|
||||||
|
displayStats(localMediaId);
|
||||||
|
}, 2500);
|
||||||
|
await setMedia(localMediaId);
|
||||||
}
|
}
|
||||||
|
|
||||||
let shareMediaId = null;
|
let shareMediaId = null;
|
||||||
|
|
Loading…
Reference in a new issue