Skip to content

Commit

Permalink
Add playback stats for WebRTC and add test codes
Browse files Browse the repository at this point in the history
  • Loading branch information
mekya committed Oct 18, 2024
1 parent 5879368 commit d33fe79
Show file tree
Hide file tree
Showing 4 changed files with 260 additions and 10 deletions.
37 changes: 34 additions & 3 deletions src/main/js/peer_stats.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,44 @@ export class PeerStats {
this.lastBytesSent = 0;

/**
* @deprecated use videoPacketsSent
* The total number of video packets sent.
* @type {number}
*/
this.totalVideoPacketsSent = 0;
/**
* The total number of video packets sent.
* @type {number}
*/
this.videoPacketsSent = 0;
/**
* The total number of video packets received.
* @type {number}
*/
this.videoPacketsReceived = 0;


/**
* The total number of audio packets sent.
* @deprecated use audioPacketsSent
* The total number of audio packets sent.
* @type {number}
*/
this.totalAudioPacketsSent = 0;

/**

/**
*
* The total number of audio packets sent.
* @type {number}
*/
this.audioPacketsSent = 0;
/*
* The total number of audio packets received.
* @type {number}
*
* */
this.audioPacketsReceived = 0;

/**
* The current timestamp.
* @type {number}
*/
Expand Down Expand Up @@ -216,6 +242,11 @@ export class PeerStats {
* @type {*[]}
*/
this.inboundRtpList = [];

/**
* The current round trip time for the candidate pair
*/
this.currentRoundTripTime = 0;
}
//kbits/sec
get averageOutgoingBitrate() {
Expand Down
28 changes: 26 additions & 2 deletions src/main/js/webrtc_adaptor.js
Original file line number Diff line number Diff line change
Expand Up @@ -1499,26 +1499,37 @@ export class WebRTCAdaptor {
var audioJitterAverageDelay = -1;
var videoJitterAverageDelay = -1;
var availableOutgoingBitrate = Infinity;
var currentRoundTripTime = -1;

var audioPacketsReceived = -1;
var videoPacketsReceived = -1;

var inboundRtp = [];

stats.forEach(value => {
//Logger.debug(value);
if (value.type == "inbound-rtp" && typeof value.kind != "undefined") {
//this is coming when webrtc playing

let inboundRtpObj = {};

inboundRtpObj.trackIdentifier = value.trackIdentifier;

bytesReceived += value.bytesReceived;
if (value.kind == "audio") {
audioPacketsLost = value.packetsLost;
audioJitter = value.jitter;
audioPacketsReceived = value.packetsReceived;

inboundRtpObj.audioPacketsLost = value.packetsLost;
} else if (value.kind == "video") {
videoPacketsLost = value.packetsLost;
inboundRtpObj.videoPacketsLost = value.packetsLost;
inboundRtpObj.framesDropped = value.framesDropped;
inboundRtpObj.framesDecoded = value.framesDecoded;
inboundRtpObj.framesPerSecond = value.framesPerSecond;
videoJitter = value.jitter;
videoPacketsReceived = value.packetsReceived;
}

inboundRtpObj.bytesReceived = value.bytesReceived;
Expand Down Expand Up @@ -1556,7 +1567,11 @@ export class WebRTCAdaptor {

inboundRtp.push(inboundRtpObj);

} else if (value.type == "outbound-rtp") {//TODO: SPLIT AUDIO AND VIDEO BITRATES
}
else if (value.type == "outbound-rtp")
{
//TODO: SPLIT AUDIO AND VIDEO BITRATES
//it is for the publishing
if (value.kind == "audio") {
audioPacketsSent = value.packetsSent;
} else if (value.kind == "video") {
Expand Down Expand Up @@ -1640,6 +1655,8 @@ export class WebRTCAdaptor {
}
else if(value.type == "candidate-pair" && value.state == "succeeded" && value.availableOutgoingBitrate !=undefined){
availableOutgoingBitrate = value.availableOutgoingBitrate/1000
//currentRoundTripTime
currentRoundTripTime = value.currentRoundTripTime;
}
});

Expand All @@ -1655,6 +1672,9 @@ export class WebRTCAdaptor {
this.remotePeerConnectionStats[streamId].totalBytesSent = bytesSent;
this.remotePeerConnectionStats[streamId].totalVideoPacketsSent = videoPacketsSent;
this.remotePeerConnectionStats[streamId].totalAudioPacketsSent = audioPacketsSent;
this.remotePeerConnectionStats[streamId].videoPacketsSent = videoPacketsSent;
this.remotePeerConnectionStats[streamId].audioPacketsSent = audioPacketsSent;

this.remotePeerConnectionStats[streamId].audioLevel = audioLevel;
this.remotePeerConnectionStats[streamId].qualityLimitationReason = qlr;
this.remotePeerConnectionStats[streamId].totalFramesEncoded = framesEncoded;
Expand All @@ -1676,9 +1696,13 @@ export class WebRTCAdaptor {
this.remotePeerConnectionStats[streamId].availableOutgoingBitrate = availableOutgoingBitrate;

this.remotePeerConnectionStats[streamId].inboundRtpList = inboundRtp;

this.remotePeerConnectionStats[streamId].currentRoundTripTime = currentRoundTripTime;
this.remotePeerConnectionStats[streamId].audioPacketsReceived = audioPacketsReceived;
this.remotePeerConnectionStats[streamId].videoPacketsReceived = videoPacketsReceived;

this.notifyEventListeners("updated_stats", this.remotePeerConnectionStats[streamId]);
resolve(true);
resolve(this.remotePeerConnectionStats[streamId]);
}).catch(err=>{
resolve(false);
});
Expand Down
7 changes: 3 additions & 4 deletions src/main/js/websocket_adaptor.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,8 @@ export class WebSocketAdaptor {

this.wsConn = new WebSocket(this.websocket_url);
this.wsConn.onopen = () => {
if (this.debug) {
Logger.debug("websocket connected");
}
Logger.debug("websocket connected");


this.pingTimerId = setInterval(() => {
this.sendPing();
Expand Down Expand Up @@ -182,7 +181,7 @@ export class WebSocketAdaptor {
}
}
catch (error) {
Logger.warn("Cannot send message:" + text);
Logger.warn("Make sure you call methods after you receive initialized callback. Cannot send message:" + text + " Error is " + error);
}
}

Expand Down
198 changes: 197 additions & 1 deletion src/test/js/webrtc_adaptor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ describe("WebRTCAdaptor", function() {
var initialized = false;

var currentTest;

var processStarted = false;

beforeEach(function() {
clock = sinon.useFakeTimers();
Expand Down Expand Up @@ -197,7 +199,7 @@ describe("WebRTCAdaptor", function() {
});


it.only("should set connected and connecting to false and log the correct message", function() {
it("should set connected and connecting to false and log the correct message", function() {

var adaptor = new WebRTCAdaptor({
websocketURL: "ws://example.com",
Expand Down Expand Up @@ -1711,6 +1713,200 @@ describe("WebRTCAdaptor", function() {


});

it("WebRTCGetStats", async function()
{

clock.restore();

this.timeout(15000);

var websocketURL = "wss://test.antmedia.io/live/websocket";
processStarted = false;
initialized = false;
var adaptor = new WebRTCAdaptor({
websocketURL: websocketURL,
callback: (info, obj) => {
console.log("callback info: " + info);
if (info == "initialized") {
initialized = true;
}
else if (info == "publish_started") {
console.log("publish started");
processStarted = true;
}
else if (info == "publish_finished") {
console.log("publish finished")
}
},
});

await new Promise((resolve, reject)=>{
setTimeout(()=> {
resolve();
}, 3000);
});

expect(initialized).to.be.true;

var streamId = "stream1desadafg23424";

adaptor.publish(streamId);

await new Promise((resolve, reject)=>{

setTimeout(()=> {
expect(processStarted).to.be.true;
resolve();
}, 3000);
});

//getStats
var peerStats = await adaptor.getStats(streamId);

console.log("publish peerStats: " + JSON.stringify(peerStats));
expect(peerStats.streamId).to.be.equal(streamId);
expect(peerStats.audioPacketsSent).to.be.above(0);
expect(peerStats.videoPacketsSent).to.be.above(0);
expect(peerStats.frameWidth).to.be.above(0);
expect(peerStats.frameHeight).to.be.above(0);
expect(peerStats.currentRoundTripTime).to.be.above(0);
expect(peerStats.currentRoundTripTime).to.be.most(1);

expect(peerStats.videoPacketsLost).to.be.least(0);
expect(peerStats.audioPacketsLost).to.be.least(0);
expect(peerStats.videoJitter).to.be.least(0);
expect(peerStats.audioJitter).to.be.least(0);
expect(peerStats.totalBytesSentCount).to.be.above(0);
expect(peerStats.lastFramesEncoded).to.be.above(0);
expect(peerStats.totalFramesEncodedCount).to.be.above(0);
expect(peerStats.frameWidth).to.be.equal(640);
expect(peerStats.frameHeight).to.be.equal(480);
expect(peerStats.qualityLimitationReason).to.be.equal("none");
expect(peerStats.firstByteSentCount).to.be.not.equal(0);
expect(peerStats.srcFps).to.be.above(0);
expect(peerStats.videoRoundTripTime).to.be.above(0);
//expect(peerStats.audioRoundTripTime).to.be.above(0);
expect(peerStats.availableOutgoingBitrate).to.be.above(0);




expect(peerStats.totalBytesReceivedCount).to.be.equal(-1);
expect(peerStats.lastBytesSent).to.be.equal(0);
expect(peerStats.videoPacketsLost).to.be.equal(0);
expect(peerStats.fractionLost).to.be.equal(-1);
expect(peerStats.startTime).to.be.not.equal(0);
expect(peerStats.lastBytesReceived).to.be.equal(0);
expect(peerStats.currentTimestamp).to.be.not.equal(0);
expect(peerStats.lastTime).to.be.equal(0);
expect(peerStats.timerId).to.be.equal(0);
expect(peerStats.firstBytesReceivedCount).to.be.equal(-1);
expect(peerStats.audioLevel).to.be.equal(-1);
expect(peerStats.resWidth).to.be.equal(640);
expect(peerStats.resHeight).to.be.equal(480);
expect(peerStats.framesReceived).to.be.equal(-1);
expect(peerStats.framesDropped).to.be.equal(-1);
expect(peerStats.framesDecoded).to.be.equal(-1);
expect(peerStats.audioJitterAverageDelay).to.be.equal(-1);
expect(peerStats.videoJitterAverageDelay).to.be.equal(-1);
expect(peerStats.inboundRtpList).to.be.empty;
expect(peerStats.audioPacketsReceived).to.be.equal(-1);
expect(peerStats.videoPacketsReceived).to.be.equal(-1);

//getStats
processStarted = false;
initialized = false;
var playAdaptor = new WebRTCAdaptor({
websocketURL: websocketURL,
callback: (info, obj) => {
console.log("callback info: " + info);
if (info == "initialized") {
initialized = true;
}
else if (info == "play_started") {
console.log("play started");
processStarted = true;
}
else if (info == "play_finished") {
console.log("play finished")
}
},
});
await new Promise((resolve, reject)=>{
setTimeout(()=> {
resolve();
}, 3000);
});

expect(initialized).to.be.true;

playAdaptor.play(streamId);

await new Promise((resolve, reject)=>{

setTimeout(()=> {
expect(processStarted).to.be.true;
resolve();
}, 3000);
});

peerStats = await playAdaptor.getStats(streamId);

console.log("play peerStats: " + JSON.stringify(peerStats));
expect(peerStats.streamId).to.be.equal(streamId);
expect(peerStats.frameWidth).to.be.equal(640);
expect(peerStats.frameHeight).to.be.equal(480);
expect(peerStats.currentRoundTripTime).to.be.above(0);
expect(peerStats.currentRoundTripTime).to.be.most(1);

expect(peerStats.videoPacketsLost).to.be.least(0);
expect(peerStats.audioPacketsLost).to.be.least(0);
expect(peerStats.videoJitter).to.be.least(0);
expect(peerStats.audioJitter).to.be.least(0);
expect(peerStats.lastFramesEncoded).to.be.equal(-1);
expect(peerStats.totalFramesEncodedCount).to.be.equal(-1);
expect(peerStats.frameWidth).to.be.equal(640);
expect(peerStats.frameHeight).to.be.equal(480);
expect(peerStats.qualityLimitationReason).to.be.equal("");
expect(peerStats.firstByteSentCount).to.be.not.equal(0);
expect(peerStats.srcFps).to.be.equal(-1);
expect(peerStats.videoRoundTripTime).to.be.equal(-1);
expect(peerStats.audioRoundTripTime).to.be.equal(-1);
expect(peerStats.availableOutgoingBitrate).to.be.above(-1);




expect(peerStats.totalBytesReceivedCount).to.be.above(0);
expect(peerStats.lastBytesSent).to.be.equal(0);
expect(peerStats.videoPacketsLost).to.be.equal(0);
//expect(peerStats.fractionLost).to.be.equal(-1);
expect(peerStats.startTime).to.be.not.equal(0);
expect(peerStats.lastBytesReceived).to.be.equal(0);
expect(peerStats.currentTimestamp).to.be.not.equal(0);
expect(peerStats.lastTime).to.be.equal(0);
expect(peerStats.timerId).to.be.equal(0);
expect(peerStats.firstBytesReceivedCount).to.be.above(0);
expect(peerStats.audioLevel).to.be.equal(-1);
expect(peerStats.resWidth).to.be.equal(-1);
expect(peerStats.resHeight).to.be.equal(-1);
expect(peerStats.framesReceived).to.be.above(0);
expect(peerStats.framesDropped).to.be.least(0);
expect(peerStats.framesDecoded).to.be.above(0);
expect(peerStats.audioJitterAverageDelay).to.be.equal(-1);
expect(peerStats.videoJitterAverageDelay).to.be.equal(-1);
expect(peerStats.audioPacketsReceived).to.be.above(0);
expect(peerStats.videoPacketsReceived).to.be.above(0);


expect(peerStats.totalBytesSentCount).to.be.equal(-1);
expect(peerStats.totalAudioPacketsSent).to.be.equal(-1);
expect(peerStats.totalVideoPacketsSent).to.be.equal(-1);



});



Expand Down

0 comments on commit d33fe79

Please sign in to comment.