1
Fork 0
mirror of https://github.com/jech/galene.git synced 2024-12-22 23:35:46 +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();
for(let i = 0; i < transceivers.length; i++) {
let t = transceivers[i];
let tid = t.sender.track && t.sender.track.id;
if(!tid)
continue;
let stid = t.sender.track && t.sender.track.id;
let rtid = t.receiver.track && t.receiver.track.id;
let report;
try {
report = await t.sender.getStats();
} catch(e) {
continue;
let report = null;
if(stid) {
try {
report = await t.sender.getStats();
} catch(e) {
}
}
stats[tid] = {};
if(report) {
for(let r of report.values()) {
if(stid && r.type === 'outbound-rtp') {
if(!('bytesSent' in r))
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;
}
}
}
for(let r of report.values()) {
if(r.type !== 'outbound-rtp')
continue;
report = null;
if(rtid) {
try {
report = await t.receiver.getStats();
} catch(e) {
console.error(e);
}
}
stats[tid].timestamp = r.timestamp;
stats[tid].bytesSent = r.bytesSent;
if(old[tid] && old[tid].timestamp) {
stats[tid].rate =
((r.bytesSent - old[tid].bytesSent) * 1000 /
(r.timestamp - old[tid].timestamp)) * 8;
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-bottom: auto;
position: relative;
border: 2px solid rgba(0,0,0,0);
}
.peer-active {
border: 2px solid #610a86;
}
.media {
@ -670,6 +675,11 @@ h1 {
margin-top: 15px;
}
.sidenav form{
display: block;
margin-top: 15px;
}
.sidenav-header h2{
color: #fff;
padding: 10px;

View file

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

View file

@ -142,6 +142,9 @@ function gotDownStream(c) {
c.onstatus = function(status) {
setMediaStatus(c);
}
c.onstats = gotDownStats;
if(document.getElementById('activitybox').value)
c.setStatsInterval(activityDetectionInterval);
}
// Store current browser viewport height in css variable
@ -278,7 +281,23 @@ document.getElementById('requestselect').onchange = function(e) {
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 text = '';
@ -286,16 +305,57 @@ function displayStats(stats) {
c.pc.getSenders().forEach(s => {
let tid = s.track && s.track.id;
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)
text = text + ' + ';
text = text + Math.round(stats.rate / 1000) + 'kbps';
text = text + Math.round(rate / 1000) + 'kbps';
}
});
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) {
console.assert(typeof(value) === 'string');
switch(value) {
@ -457,7 +517,7 @@ async function addLocalMedia(id) {
let sender = c.pc.addTrack(t, stream);
});
c.onstats = displayStats;
c.onstats = gotUpStats;
c.setStatsInterval(2000);
await setMedia(c, true);
setButtonsVisibility();
@ -486,7 +546,7 @@ async function addShareMedia(setup) {
};
c.labels[t.id] = 'screenshare';
});
c.onstats = displayStats;
c.onstats = gotUpStats;
c.setStatsInterval(2000);
await setMedia(c, true);
setButtonsVisibility()