mirror of
https://github.com/jech/galene.git
synced 2024-11-26 02:25:58 +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();
|
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;
|
||||||
try {
|
if(stid) {
|
||||||
report = await t.sender.getStats();
|
try {
|
||||||
} catch(e) {
|
report = await t.sender.getStats();
|
||||||
continue;
|
} 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()) {
|
report = null;
|
||||||
if(r.type !== 'outbound-rtp')
|
if(rtid) {
|
||||||
continue;
|
try {
|
||||||
|
report = await t.receiver.getStats();
|
||||||
|
} catch(e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
stats[tid].timestamp = r.timestamp;
|
if(report) {
|
||||||
stats[tid].bytesSent = r.bytesSent;
|
for(let r of report.values()) {
|
||||||
if(old[tid] && old[tid].timestamp) {
|
if(rtid && r.type === 'track') {
|
||||||
stats[tid].rate =
|
if(!('totalAudioEnergy' in r))
|
||||||
((r.bytesSent - old[tid].bytesSent) * 1000 /
|
continue;
|
||||||
(r.timestamp - old[tid].timestamp)) * 8;
|
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-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;
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in a new issue