Skip to content

Commit

Permalink
ref(QualityController) Add recovery mechanism and adjust the resoluti…
Browse files Browse the repository at this point in the history
…on check.

Impl a recovery mechanism for the lastN to be increased if the cpu limitation goes away and doesn't return after increasing lastN. Also, additionally improve the calculation of the expected resolution taking simulcast stream resolutions into account.
  • Loading branch information
jallamsetty1 committed Jul 24, 2024
1 parent a9b6dd7 commit 43c750c
Show file tree
Hide file tree
Showing 7 changed files with 517 additions and 196 deletions.
2 changes: 1 addition & 1 deletion JitsiConference.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import E2ePing from './modules/e2eping/e2eping';
import Jvb121EventGenerator from './modules/event/Jvb121EventGenerator';
import FeatureFlags from './modules/flags/FeatureFlags';
import { LiteModeContext } from './modules/litemode/LiteModeContext';
import QualityController from './modules/qualitycontrol/QualityController';
import { QualityController } from './modules/qualitycontrol/QualityController';
import RecordingManager from './modules/recording/RecordingManager';
import Settings from './modules/settings/Settings';
import AudioOutputProblemDetector from './modules/statistics/AudioOutputProblemDetector';
Expand Down
17 changes: 17 additions & 0 deletions modules/RTC/MockClasses.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,14 @@ export class MockPeerConnection {
return Promise.resolve(/* answer */{});
}

/**
* {@link TraceablePeerConnection.doesTrueSimulcast}.
* @returns {boolean}
*/
doesTrueSimulcast() {
return false;
}

/**
* Returns the list of the codecs negotiated.
* @returns {Array<string>}
Expand Down Expand Up @@ -240,9 +248,18 @@ export class MockRTC extends Listenable {
*/
createPeerConnection() {
this.pc = new MockPeerConnection();
this.forwardedSources = [];

return this.pc;
}

/**
* Returns the list of sources that the bridge is forwarding to the client.
* @returns {Array<string>}
*/
getForwardedSources() {
return this.forwardedSources;
}
}

/**
Expand Down
163 changes: 23 additions & 140 deletions modules/qualitycontrol/CodecSelection.spec.js
Original file line number Diff line number Diff line change
@@ -1,123 +1,12 @@
import * as JitsiConferenceEvents from '../../JitsiConferenceEvents';
import { MockRTC, MockSignalingLayerImpl } from '../RTC/MockClasses';
import Listenable from '../util/Listenable';
import { MockRTC } from '../RTC/MockClasses';
import { nextTick } from '../util/TestUtils';
import JingleSessionPC from '../xmpp/JingleSessionPC';
import { MockChatRoom, MockStropheConnection } from '../xmpp/MockClasses';

import QualityController from './QualityController';

/**
* MockParticipant
*/
class MockParticipant {
/**
* A constructor...
*/
constructor(id) {
this.id = id;
}

/**
* Returns the endpoint id of the participant.
* @returns <string>
*/
getId() {
return this.id;
}
}

/**
* MockLocalTrack
*/
class MockLocalTrack {
/**
* Constructor
* @param {number} resolution
* @param {string} videoType
*/
constructor(resolution, videoType) {
this.maxEnabledResolution = resolution;
this.videoType = videoType;
}

/**
* Returns the video type of the mock local track.
* @returns {string}
*/
getVideoType() {
return this.videoType;
}
}

/**
* MockConference
*/
class MockConference extends Listenable {
/**
* A constructor...
*/
constructor() {
super();
this.options = {
config: {}
};

this.activeMediaSession = undefined;
this.mediaSessions = [];
this.participants = [];
this._signalingLayer = new MockSignalingLayerImpl();
}

/**
* Add a mock participant to the conference
* @param {MockParticipant} participant
* @param {Array<string>} codecList
* @param {String} codecType
*/
addParticipant(participant, codecList, codecType) {
this.participants.push(participant);
this._signalingLayer.setPeerMediaInfo(true, participant.getId(), codecList, codecType);
this.eventEmitter.emit(JitsiConferenceEvents.USER_JOINED);
}

/**
* Returns the active media session.
* @returns {JingleSessionPC}
*/
getActiveMediaSession() {
return this.jvbJingleSession;
}

/**
* Returns the list of participants.
* @returns Array<MockParticipant>
*/
getParticipants() {
return this.participants;
}

/**
* Checks if E2EE is enabled.
* @returns {boolean}
*/
isE2EEEnabled() {
return false;
}

/**
* Removes the participant from the conference.
* @param {MockParticipant} endpoint
*/
removeParticipant(endpoint) {
this.participants = this.participants.filter(p => p !== endpoint);
this._signalingLayer.setPeerMediaInfo(false, endpoint.getId());
this.eventEmitter.emit(JitsiConferenceEvents.USER_LEFT);
}
}
import { MockConference, MockLocalTrack, MockParticipant } from './MockClasses';
import { QualityController } from './QualityController';

describe('Codec Selection', () => {
/* eslint-disable-next-line no-unused-vars */
let qualityController;
let conference;
let connection;
Expand All @@ -128,7 +17,8 @@ describe('Codec Selection', () => {
const SID = 'sid12345';

beforeEach(() => {
conference = new MockConference();
rtc = new MockRTC();
conference = new MockConference(rtc);
connection = new MockStropheConnection();
jingleSession = new JingleSessionPC(
SID,
Expand All @@ -140,15 +30,12 @@ describe('Codec Selection', () => {
false,
false);

rtc = new MockRTC();

jingleSession.initialize(
/* ChatRoom */ new MockChatRoom(),
/* RTC */ rtc,
/* Signaling layer */ conference._signalingLayer,
/* options */ { });
conference.jvbJingleSession = jingleSession;
conference.rtc = rtc;
});

describe('when codec preference list is used in config.js', () => {
Expand Down Expand Up @@ -275,8 +162,8 @@ describe('Codec Selection', () => {
jasmine.clock().uninstall();
});

it('and encode resolution is limited by cpu for camera tracks', () => {
const localTrack = new MockLocalTrack(720, 'camera');
it('and encode resolution is limited by cpu for camera tracks', async () => {
const localTrack = new MockLocalTrack('1', 720, 'camera');

participant1 = new MockParticipant('remote-1');
conference.addParticipant(participant1, [ 'av1', 'vp9', 'vp8' ]);
Expand All @@ -288,20 +175,18 @@ describe('Codec Selection', () => {

qualityController.codecController.changeCodecPreferenceOrder(localTrack, 'av1');

return nextTick(121000).then(() => {
expect(jingleSession.setVideoCodecs).toHaveBeenCalledWith([ 'vp9', 'av1', 'vp8' ], undefined);
})
.then(() => {
participant3 = new MockParticipant('remote-3');
conference.addParticipant(participant3, [ 'av1', 'vp9', 'vp8' ]);
await nextTick(121000);
expect(jingleSession.setVideoCodecs).toHaveBeenCalledWith([ 'vp9', 'av1', 'vp8' ], undefined);

participant3 = new MockParticipant('remote-3');
conference.addParticipant(participant3, [ 'av1', 'vp9', 'vp8' ]);

// Expect the local endpoint to continue sending VP9.
expect(jingleSession.setVideoCodecs).toHaveBeenCalledWith([ 'vp9', 'av1', 'vp8' ], undefined);
});
// Expect the local endpoint to continue sending VP9.
expect(jingleSession.setVideoCodecs).toHaveBeenCalledWith([ 'vp9', 'av1', 'vp8' ], undefined);
});

it('and does not change codec if the current codec is already the lowest complexity codec', () => {
const localTrack = new MockLocalTrack(720, 'camera');
it('and does not change codec if the current codec is already the lowest complexity codec', async () => {
const localTrack = new MockLocalTrack('1', 720, 'camera');

qualityController.codecController.codecPreferenceOrder.jvb = [ 'vp8', 'vp9', 'av1' ];

Expand All @@ -315,16 +200,14 @@ describe('Codec Selection', () => {

qualityController.codecController.changeCodecPreferenceOrder(localTrack, 'vp8');

return nextTick(121000).then(() => {
expect(jingleSession.setVideoCodecs).toHaveBeenCalledWith([ 'vp8', 'vp9', 'av1' ], undefined);
})
.then(() => {
participant3 = new MockParticipant('remote-3');
conference.addParticipant(participant3, [ 'av1', 'vp9', 'vp8' ]);
await nextTick(121000);
expect(jingleSession.setVideoCodecs).toHaveBeenCalledWith([ 'vp8', 'vp9', 'av1' ], undefined);

participant3 = new MockParticipant('remote-3');
conference.addParticipant(participant3, [ 'av1', 'vp9', 'vp8' ]);

// Expect the local endpoint to continue sending VP9.
expect(jingleSession.setVideoCodecs).toHaveBeenCalledWith([ 'vp8', 'vp9', 'av1' ], undefined);
});
// Expect the local endpoint to continue sending VP9.
expect(jingleSession.setVideoCodecs).toHaveBeenCalledWith([ 'vp8', 'vp9', 'av1' ], undefined);
});
});
});
Loading

0 comments on commit 43c750c

Please sign in to comment.