1
Fork 0
mirror of https://github.com/jech/galene.git synced 2024-11-23 00:55:58 +01:00

Implement activity detection.

This commit is contained in:
Juliusz Chroboczek 2020-09-11 23:20:46 +02:00
parent d35f599922
commit 5c97e739a6
4 changed files with 127 additions and 23 deletions

View file

@ -919,29 +919,59 @@ Stream.prototype.updateStats = async function() {
let transceivers = c.pc.getTransceivers(); let transceivers = c.pc.getTransceivers();
for(let i = 0; i < transceivers.length; i++) { for(let i = 0; i < transceivers.length; i++) {
let t = transceivers[i]; let t = transceivers[i];
let tid = t.sender.track && t.sender.track.id; let stid = t.sender.track && t.sender.track.id;
if(!tid) let rtid = t.receiver.track && t.receiver.track.id;
continue;
let report; let report = null;
if(stid) {
try { try {
report = await t.sender.getStats(); report = await t.sender.getStats();
} catch(e) { } catch(e) {
continue; }
} }
stats[tid] = {}; if(report) {
for(let r of report.values()) { for(let r of report.values()) {
if(r.type !== 'outbound-rtp') if(stid && r.type === 'outbound-rtp') {
if(!('bytesSent' in r))
continue; continue;
if(!stats[stid])
stats[stid] = {};
stats[stid][r.type] = {};
stats[stid][r.type].timestamp = r.timestamp;
stats[stid][r.type].bytesSent = r.bytesSent;
if(old[stid] && old[stid][r.type])
stats[stid][r.type].rate =
((r.bytesSent - old[stid][r.type].bytesSent) * 1000 /
(r.timestamp - old[stid][r.type].timestamp)) * 8;
}
}
}
stats[tid].timestamp = r.timestamp; report = null;
stats[tid].bytesSent = r.bytesSent; if(rtid) {
if(old[tid] && old[tid].timestamp) { try {
stats[tid].rate = report = await t.receiver.getStats();
((r.bytesSent - old[tid].bytesSent) * 1000 / } catch(e) {
(r.timestamp - old[tid].timestamp)) * 8; console.error(e);
}
}
if(report) {
for(let r of report.values()) {
if(rtid && r.type === 'track') {
if(!('totalAudioEnergy' in r))
continue;
if(!stats[rtid])
stats[rtid] = {};
stats[rtid][r.type] = {};
stats[rtid][r.type].timestamp = r.timestamp;
stats[rtid][r.type].totalAudioEnergy = r.totalAudioEnergy;
if(old[rtid] && old[rtid][r.type])
stats[rtid][r.type].audioEnergy =
(r.totalAudioEnergy - old[rtid][r.type].totalAudioEnergy) * 1000 /
(r.timestamp - old[rtid][r.type].timestamp);
}
} }
} }
} }

View file

@ -610,6 +610,11 @@ h1 {
margin-top: auto; margin-top: auto;
margin-bottom: auto; margin-bottom: auto;
position: relative; position: relative;
border: 2px solid rgba(0,0,0,0);
}
.peer-active {
border: 2px solid #610a86;
} }
.media { .media {
@ -670,6 +675,11 @@ h1 {
margin-top: 15px; margin-top: 15px;
} }
.sidenav form{
display: block;
margin-top: 15px;
}
.sidenav-header h2{ .sidenav-header h2{
color: #fff; color: #fff;
padding: 10px; padding: 10px;

View file

@ -172,6 +172,10 @@
<option value="screenshare">screen share</option> <option value="screenshare">screen share</option>
<option value="everything" selected>everything</option> <option value="everything" selected>everything</option>
</select> </select>
<form>
<input id="activitybox" type="checkbox">Activity detection</input>
</form>
</div> </div>
</div> </div>

View file

@ -142,6 +142,9 @@ function gotDownStream(c) {
c.onstatus = function(status) { c.onstatus = function(status) {
setMediaStatus(c); setMediaStatus(c);
} }
c.onstats = gotDownStats;
if(document.getElementById('activitybox').value)
c.setStatsInterval(activityDetectionInterval);
} }
// Store current browser viewport height in css variable // Store current browser viewport height in css variable
@ -278,7 +281,23 @@ document.getElementById('requestselect').onchange = function(e) {
serverConnection.request(this.value); serverConnection.request(this.value);
}; };
function displayStats(stats) { const activityDetectionInterval = 100;
const activityDetectionPeriod = 700;
const activityDetectionThreshold = 0.2;
document.getElementById('activitybox').onchange = function(e) {
for(let id in serverConnection.down) {
let c = serverConnection.down[id];
if(this.value)
c.setStatsInterval(activityDetectionInterval);
else {
setActive(c, false);
c.setStatsInterval(0);
}
}
}
function gotUpStats(stats) {
let c = this; let c = this;
let text = ''; let text = '';
@ -286,16 +305,57 @@ function displayStats(stats) {
c.pc.getSenders().forEach(s => { c.pc.getSenders().forEach(s => {
let tid = s.track && s.track.id; let tid = s.track && s.track.id;
let stats = tid && c.stats[tid]; let stats = tid && c.stats[tid];
if(stats && stats.rate > 0) { let rate = stats && stats['outbound-rtp'] && stats['outbound-rtp'].rate;
if(typeof rate === 'number') {
if(text) if(text)
text = text + ' + '; text = text + ' + ';
text = text + Math.round(stats.rate / 1000) + 'kbps'; text = text + Math.round(rate / 1000) + 'kbps';
} }
}); });
setLabel(c, text); setLabel(c, text);
} }
/**
* @param {Stream} c
* @param {boolean} value
*/
function setActive(c, value) {
let peer = document.getElementById('peer-' + c.id);
if(value)
peer.classList.add('peer-active');
else
peer.classList.remove('peer-active');
}
function gotDownStats(stats) {
if(!document.getElementById('activitybox').value)
return;
let c = this;
let maxEnergy = 0;
c.pc.getReceivers().forEach(r => {
let tid = r.track && r.track.id;
let s = tid && stats[tid];
let energy = s && s['track'] && s['track'].audioEnergy;
if(typeof energy === 'number')
maxEnergy = Math.max(maxEnergy, energy);
});
// totalAudioEnergy is defined as the integral of the square of the
// volume, so square the threshold.
if(maxEnergy > activityDetectionThreshold * activityDetectionThreshold) {
c.userdata.lastVoiceActivity = Date.now();
setActive(c, true);
} else {
let last = c.userdata.lastVoiceActivity;
if(!last || Date.now() - last > activityDetectionPeriod)
setActive(c, false);
}
}
function mapMediaOption(value) { function mapMediaOption(value) {
console.assert(typeof(value) === 'string'); console.assert(typeof(value) === 'string');
switch(value) { switch(value) {
@ -457,7 +517,7 @@ async function addLocalMedia(id) {
let sender = c.pc.addTrack(t, stream); let sender = c.pc.addTrack(t, stream);
}); });
c.onstats = displayStats; c.onstats = gotUpStats;
c.setStatsInterval(2000); c.setStatsInterval(2000);
await setMedia(c, true); await setMedia(c, true);
setButtonsVisibility(); setButtonsVisibility();
@ -486,7 +546,7 @@ async function addShareMedia(setup) {
}; };
c.labels[t.id] = 'screenshare'; c.labels[t.id] = 'screenshare';
}); });
c.onstats = displayStats; c.onstats = gotUpStats;
c.setStatsInterval(2000); c.setStatsInterval(2000);
await setMedia(c, true); await setMedia(c, true);
setButtonsVisibility() setButtonsVisibility()