Skip to content

Commit

Permalink
fix(plugin-meetings): streamline is active speaker mqa (#3597)
Browse files Browse the repository at this point in the history
Co-authored-by: evujici <[email protected]>
  • Loading branch information
edvujic and evujici authored Jul 5, 2024
1 parent 3c72eb3 commit 7ccbeca
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ export const emptyVideoReceiveStream = {
ssci: 0, // Not avaliable
},
h264CodecProfile: 'BP',
isActiveSpeaker: true,
isActiveSpeaker: false,
optimalFrameSize: 0, // Not avaliable
receivedFrameSize: 0,
receivedHeight: 0,
Expand Down
6 changes: 6 additions & 0 deletions packages/@webex/plugin-meetings/src/statsAnalyzer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1107,6 +1107,12 @@ export class StatsAnalyzer extends EventsScope {
}
}

if (mediaType.startsWith('video-recv')) {
this.statsResults[mediaType][sendrecvType].isActiveSpeaker = result.isActiveSpeaker;
this.statsResults[mediaType][sendrecvType].lastActiveSpeakerTimestamp =
result.lastActiveSpeakerUpdateTimestamp;
}

// Check the over all packet Lost ratio
this.statsResults[mediaType][sendrecvType].currentPacketLossRatio =
currentPacketsLost > 0
Expand Down
8 changes: 8 additions & 0 deletions packages/@webex/plugin-meetings/src/statsAnalyzer/mqaUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,14 @@ export const getVideoReceiverStreamMqa = ({
statsResults[mediaType][sendrecvType].keyFramesDecoded - lastKeyFramesDecoded || 0;
videoReceiverStream.requestedKeyFrames =
statsResults[mediaType][sendrecvType].totalPliCount - lastPliCount || 0;

videoReceiverStream.isActiveSpeaker =
statsResults[mediaType][sendrecvType].isActiveSpeaker ||
((statsResults[mediaType][sendrecvType].lastActiveSpeakerTimestamp ?? 0) > 0 &&
performance.now() +
performance.timeOrigin -
(statsResults[mediaType][sendrecvType].lastActiveSpeakerTimestamp ?? 0) <
MQA_INTERVAL);
};

export const getVideoSenderMqa = ({videoSender, statsResults, lastMqaDataSent, baseMediaType}) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,8 @@ describe('plugin-meetings', () => {
packetsReceived: 0,
isRequested: true,
lastRequestedUpdateTimestamp: 0,
isActiveSpeaker: false,
lastActiveSpeakerUpdateTimestamp: 0,
},
{
type: 'remote-outbound-rtp',
Expand Down Expand Up @@ -1467,7 +1469,7 @@ describe('plugin-meetings', () => {
framesDropped: 0,
},
h264CodecProfile: 'BP',
isActiveSpeaker: true,
isActiveSpeaker: false,
optimalFrameSize: 0,
receivedFrameSize: 3600,
receivedHeight: 720,
Expand Down Expand Up @@ -1501,7 +1503,7 @@ describe('plugin-meetings', () => {
framesDropped: 0,
},
h264CodecProfile: 'BP',
isActiveSpeaker: true,
isActiveSpeaker: false,
optimalFrameSize: 0,
receivedFrameSize: 3600,
receivedHeight: 720,
Expand Down Expand Up @@ -1565,7 +1567,7 @@ describe('plugin-meetings', () => {
framesDropped: 0,
},
h264CodecProfile: 'BP',
isActiveSpeaker: true,
isActiveSpeaker: false,
optimalFrameSize: 0,
receivedFrameSize: 3600,
receivedHeight: 720,
Expand Down Expand Up @@ -1597,7 +1599,7 @@ describe('plugin-meetings', () => {
framesDropped: 0,
},
h264CodecProfile: 'BP',
isActiveSpeaker: true,
isActiveSpeaker: false,
optimalFrameSize: 0,
receivedFrameSize: 3600,
receivedHeight: 720,
Expand Down Expand Up @@ -1629,7 +1631,7 @@ describe('plugin-meetings', () => {
framesDropped: 0,
},
h264CodecProfile: 'BP',
isActiveSpeaker: true,
isActiveSpeaker: false,
optimalFrameSize: 0,
receivedFrameSize: 3600,
receivedHeight: 720,
Expand Down Expand Up @@ -1724,7 +1726,7 @@ describe('plugin-meetings', () => {
requestedFrames: 0,
rtpPackets: 0,
ssci: 0,
transmittedBitrate: 0.13333333333333333,
transmittedBitrate: 0.13333333333333333,
transmittedFrameRate: 0
},
h264CodecProfile: 'BP',
Expand Down Expand Up @@ -1828,6 +1830,39 @@ describe('plugin-meetings', () => {
}
]);
});
describe('active speaker status emission', async () => {
beforeEach(async () => {
await startStatsAnalyzer();
performance.timeOrigin = 1;
});

it('reports active speaker as true when the participant has been speaking', async () => {
fakeStats.video.receivers[0].report[0].isActiveSpeaker = true;
await progressTime(5 * MQA_INTERVAL);
assert.strictEqual(mqeData.videoReceive[0].streams[0].isActiveSpeaker, true);
});

it('reports active speaker as false when the participant has not spoken', async () => {
fakeStats.video.receivers[0].report[0].isActiveSpeaker = false;
await progressTime(5 * MQA_INTERVAL);
assert.strictEqual(mqeData.videoReceive[0].streams[0].isActiveSpeaker, false);
});

it('defaults to false when active speaker status is indeterminate', async () => {
fakeStats.video.receivers[0].report[0].isActiveSpeaker = undefined;
await progressTime(MQA_INTERVAL);
assert.strictEqual(mqeData.videoReceive[0].streams[0].isActiveSpeaker, false);
});

it('updates active speaker to true following a recent status change to speaking', async () => {
fakeStats.video.receivers[0].report[0].isActiveSpeaker = false;
fakeStats.video.receivers[0].report[0].lastActiveSpeakerUpdateTimestamp = performance.timeOrigin + performance.now() + (30 * 1000);
await progressTime(MQA_INTERVAL);
assert.strictEqual(mqeData.videoReceive[0].streams[0].isActiveSpeaker, true);
await progressTime(MQA_INTERVAL);
assert.strictEqual(mqeData.videoReceive[0].streams[0].isActiveSpeaker, false);
});
});
describe('sends streams according to their is requested flag', async () => {

beforeEach(async () => {
Expand Down Expand Up @@ -1864,4 +1899,4 @@ describe('plugin-meetings', () => {
});
})
});
})
});

0 comments on commit 7ccbeca

Please sign in to comment.