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:
parent
d35f599922
commit
5c97e739a6
4 changed files with 127 additions and 23 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in a new issue