mirror of
https://github.com/jech/galene.git
synced 2024-12-22 23:35:46 +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;
|
||||
}
|
||||
|
||||
#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 {
|
||||
display: flex;
|
||||
}
|
||||
|
@ -111,6 +127,7 @@ h1 {
|
|||
}
|
||||
|
||||
#input {
|
||||
margin-left: 0.5em;
|
||||
width: 100%;
|
||||
border: none;
|
||||
resize: none;
|
||||
|
|
|
@ -31,8 +31,22 @@
|
|||
<div id="optionsdiv">
|
||||
<label for="presenterbox">Present:</label>
|
||||
<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>
|
||||
<input id="sharebox" type="checkbox"/ disabled>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
130
static/sfu.js
130
static/sfu.js
|
@ -126,6 +126,16 @@ document.getElementById('presenterbox').onchange = function(e) {
|
|||
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) {
|
||||
e.preventDefault();
|
||||
setShareMedia(this.checked);
|
||||
|
@ -193,6 +203,71 @@ function displayStats(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;
|
||||
|
||||
async function setLocalMedia(setup) {
|
||||
|
@ -209,32 +284,39 @@ async function setLocalMedia(setup) {
|
|||
return;
|
||||
}
|
||||
|
||||
if(!localMediaId) {
|
||||
let constraints = {audio: true, video: true};
|
||||
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 audio = mapMediaOption(document.getElementById('audioselect').value);
|
||||
let video = mapMediaOption(document.getElementById('videoselect').value);
|
||||
|
||||
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);
|
||||
setLocalMedia(false);
|
||||
if(!audio && !video)
|
||||
return;
|
||||
|
||||
let constraints = {audio: audio, video: video};
|
||||
let stream = null;
|
||||
try {
|
||||
stream = await navigator.mediaDevices.getUserMedia(constraints);
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
document.getElementById('presenterbox').checked = false;
|
||||
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;
|
||||
|
|
Loading…
Reference in a new issue