Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

QualityController.spec.js 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. import { MockPeerConnection, MockRTC } from '../RTC/MockClasses';
  2. import { nextTick } from '../util/TestUtils';
  3. import { MockConference, MockLocalTrack } from './MockClasses';
  4. import { FixedSizeArray, QualityController } from './QualityController';
  5. describe('QualityController', () => {
  6. let qualityController;
  7. let conference;
  8. let data;
  9. let localTrack;
  10. let options;
  11. let rtc;
  12. let sourceStats;
  13. let tpc;
  14. let updatedStats;
  15. beforeEach(() => {
  16. rtc = new MockRTC();
  17. conference = new MockConference(rtc);
  18. tpc = new MockPeerConnection();
  19. });
  20. describe('When adaptive mode is enabled', () => {
  21. beforeEach(() => {
  22. options = {
  23. enableAdaptiveMode: true,
  24. jvb: {
  25. preferenceOrder: [ 'VP9', 'VP8', 'H264' ],
  26. screenshareCodec: 'VP9'
  27. },
  28. lastNRampupTime: 60000,
  29. p2p: {}
  30. };
  31. localTrack = new MockLocalTrack('1', 720, 'camera');
  32. qualityController = new QualityController(conference, options);
  33. sourceStats = {
  34. avgEncodeTime: 12,
  35. codec: 'VP8',
  36. encodeResolution: 360,
  37. qualityLimitationReason: 'cpu',
  38. localTrack,
  39. timestamp: 1,
  40. tpc
  41. };
  42. qualityController._encodeTimeStats = new Map();
  43. data = new FixedSizeArray(10);
  44. data.add(sourceStats);
  45. qualityController._encodeTimeStats.set(localTrack.rtcId, data);
  46. jasmine.clock().install();
  47. spyOn(qualityController.receiveVideoController, 'setLastN');
  48. });
  49. afterEach(() => {
  50. jasmine.clock().uninstall();
  51. });
  52. it('and the client encounters cpu limitation', async () => {
  53. // Start with 10 sources being received.
  54. rtc.forwardedSources = [ 'v1', 'v2', 'v3', 'v4', 'v5', 'v6', 'v7', 'v8', 'v9', 'v10' ];
  55. qualityController.receiveVideoController._lastN = 25;
  56. qualityController._performQualityOptimizations(sourceStats);
  57. // When a cpu limitation is reported for the first time with the lowest complexity codec, the number of
  58. // received videos will be halved.
  59. expect(qualityController.receiveVideoController.setLastN).toHaveBeenCalledWith(5);
  60. qualityController.receiveVideoController._lastN = 5;
  61. rtc.forwardedSources = [ 'v1', 'v2', 'v3', 'v4', 'v5' ];
  62. // If the stats continue to show a cpu limitation, the lastN value will be further dropped.
  63. qualityController._performQualityOptimizations(sourceStats);
  64. expect(qualityController.receiveVideoController.setLastN).toHaveBeenCalledWith(3);
  65. rtc.forwardedSources = [ 'v1', 'v2', 'v3' ];
  66. qualityController.receiveVideoController._lastN = 3;
  67. // If the stats indicate that the cpu limitation ceases to exist, the lastN value will be incremented by 1
  68. // if the stats continue to look good for the next 60 secs.
  69. updatedStats = {
  70. avgEncodeTime: 8,
  71. codec: 'VP8',
  72. encodeResolution: 720,
  73. qualityLimitationReason: 'none',
  74. localTrack,
  75. timestamp: 2,
  76. tpc
  77. };
  78. data = qualityController._encodeTimeStats.get(localTrack.rtcId);
  79. data.add(updatedStats);
  80. qualityController._performQualityOptimizations(updatedStats);
  81. // Wait for atleast 60 secs and check if lastN value was incremented.
  82. await nextTick(61000);
  83. expect(qualityController.receiveVideoController.setLastN).toHaveBeenCalledWith(4);
  84. rtc.forwardedSources = [ 'v1', 'v2', 'v3', 'v4' ];
  85. qualityController.receiveVideoController._lastN = 4;
  86. // Stats continue to indicate that there is no cpu limitation.
  87. updatedStats = {
  88. avgEncodeTime: 8,
  89. codec: 'VP8',
  90. encodeResolution: 720,
  91. qualityLimitationReason: 'none',
  92. localTrack,
  93. timestamp: 3,
  94. tpc
  95. };
  96. data = qualityController._encodeTimeStats.get(localTrack.rtcId);
  97. data.add(updatedStats);
  98. qualityController._performQualityOptimizations(updatedStats);
  99. await nextTick(30000);
  100. // However, cpu limitation is reported 30 secs after the lastN is bumped to 4 which indicates that it
  101. // is a direct consequence of the lastN value going up. Therefore, client will not make any more attempts
  102. // to raise the lastN value even if the cpu limitation is gone.
  103. updatedStats = {
  104. avgEncodeTime: 12,
  105. codec: 'VP8',
  106. encodeResolution: 360,
  107. qualityLimitationReason: 'cpu',
  108. localTrack,
  109. timestamp: 4,
  110. tpc
  111. };
  112. data = qualityController._encodeTimeStats.get(localTrack.rtcId);
  113. data.add(updatedStats);
  114. qualityController._performQualityOptimizations(updatedStats);
  115. // Check that further ramp ups are blocked and lastN value is dropped to 3.
  116. expect(qualityController._isLastNRampupBlocked).toBeTrue();
  117. expect(qualityController.receiveVideoController.setLastN).toHaveBeenCalledWith(3);
  118. rtc.forwardedSources = [ 'v1', 'v2', 'v3' ];
  119. qualityController.receiveVideoController._lastN = 3;
  120. // Even if the limitation is removed one more time, check if the client continues to operate at the current
  121. // lastN value.
  122. updatedStats = {
  123. avgEncodeTime: 8,
  124. codec: 'VP8',
  125. encodeResolution: 720,
  126. qualityLimitationReason: 'none',
  127. localTrack,
  128. timestamp: 5,
  129. tpc
  130. };
  131. data = qualityController._encodeTimeStats.get(localTrack.rtcId);
  132. data.add(updatedStats);
  133. qualityController._performQualityOptimizations(updatedStats);
  134. await nextTick(61000);
  135. expect(qualityController.receiveVideoController.setLastN).toHaveBeenCalledWith(3);
  136. });
  137. });
  138. describe('When adaptive mode is disabled', () => {
  139. beforeEach(() => {
  140. options = {
  141. enableAdaptiveMode: false,
  142. jvb: {},
  143. lastNRampupTime: 60000,
  144. p2p: {}
  145. };
  146. localTrack = new MockLocalTrack('1', 720, 'camera');
  147. qualityController = new QualityController(conference, options);
  148. sourceStats = {
  149. avgEncodeTime: 12,
  150. codec: 'VP8',
  151. encodeResolution: 360,
  152. qualityLimitationReason: 'cpu',
  153. localTrack,
  154. timestamp: 1,
  155. tpc
  156. };
  157. qualityController._encodeTimeStats = new Map();
  158. data = new FixedSizeArray(10);
  159. data.add(sourceStats);
  160. qualityController._encodeTimeStats.set(localTrack.rtcId, data);
  161. jasmine.clock().install();
  162. spyOn(qualityController.receiveVideoController, 'setLastN');
  163. });
  164. afterEach(() => {
  165. jasmine.clock().uninstall();
  166. });
  167. it('and the client encounters cpu limitation with lowest complexity codec', async () => {
  168. // Start with 10 sources being received.
  169. rtc.forwardedSources = [ 'v1', 'v2', 'v3', 'v4', 'v5', 'v6', 'v7', 'v8', 'v9', 'v10' ];
  170. qualityController.receiveVideoController._lastN = 25;
  171. qualityController._performQualityOptimizations(sourceStats);
  172. expect(qualityController.receiveVideoController.setLastN).toHaveBeenCalledTimes(0);
  173. });
  174. });
  175. });