You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Participant.ts 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. /* global APP $ */
  2. import { multiremotebrowser } from '@wdio/globals';
  3. import { IConfig } from '../../react/features/base/config/configType';
  4. import { urlObjectToString } from '../../react/features/base/util/uri';
  5. import Filmstrip from '../pageobjects/Filmstrip';
  6. import Toolbar from '../pageobjects/Toolbar';
  7. import { LOG_PREFIX, logInfo } from './browserLogger';
  8. import { IContext } from './participants';
  9. /**
  10. * Participant.
  11. */
  12. export class Participant {
  13. /**
  14. * The current context.
  15. *
  16. * @private
  17. */
  18. private context: { roomName: string; };
  19. private _name: string;
  20. private _endpointId: string;
  21. /**
  22. * The default config to use when joining.
  23. *
  24. * @private
  25. */
  26. private config = {
  27. analytics: {
  28. disabled: true
  29. },
  30. debug: true,
  31. requireDisplayName: false,
  32. testing: {
  33. testMode: true
  34. },
  35. disableAP: true,
  36. disable1On1Mode: true,
  37. disableModeratorIndicator: true,
  38. enableTalkWhileMuted: false,
  39. gatherStats: true,
  40. p2p: {
  41. enabled: false,
  42. useStunTurn: false
  43. },
  44. pcStatsInterval: 1500,
  45. prejoinConfig: {
  46. enabled: false
  47. },
  48. toolbarConfig: {
  49. alwaysVisible: true
  50. }
  51. } as IConfig;
  52. /**
  53. * Creates a participant with given name.
  54. *
  55. * @param {string} name - The name of the participant.
  56. */
  57. constructor(name: string) {
  58. this._name = name;
  59. }
  60. /**
  61. * Returns participant endpoint ID.
  62. *
  63. * @returns {Promise<string>} The endpoint ID.
  64. */
  65. async getEndpointId() {
  66. if (!this._endpointId) {
  67. this._endpointId = await this.driver.execute(() => { // eslint-disable-line arrow-body-style
  68. return APP.conference.getMyUserId();
  69. });
  70. }
  71. return this._endpointId;
  72. }
  73. /**
  74. * The driver it uses.
  75. */
  76. get driver() {
  77. return multiremotebrowser.getInstance(this._name);
  78. }
  79. /**
  80. * The name.
  81. */
  82. get name() {
  83. return this._name;
  84. }
  85. /**
  86. * Adds a log to the participants log file.
  87. *
  88. * @param {string} message - The message to log.
  89. * @returns {void}
  90. */
  91. log(message: string) {
  92. logInfo(this.driver, message);
  93. }
  94. /**
  95. * Joins conference.
  96. *
  97. * @param {IContext} context - The context.
  98. * @param {boolean} skipInMeetingChecks - Whether to skip in meeting checks.
  99. * @returns {Promise<void>}
  100. */
  101. async joinConference(context: IContext, skipInMeetingChecks = false) {
  102. this.context = context;
  103. const url = urlObjectToString({
  104. room: context.roomName,
  105. configOverwrite: this.config,
  106. interfaceConfigOverwrite: {
  107. SHOW_CHROME_EXTENSION_BANNER: false
  108. },
  109. userInfo: {
  110. displayName: this._name
  111. }
  112. }) || '';
  113. await this.driver.setTimeout({ 'pageLoad': 30000 });
  114. await this.driver.url(url);
  115. await this.waitForPageToLoad();
  116. await this.waitToJoinMUC();
  117. await this.postLoadProcess(skipInMeetingChecks);
  118. }
  119. /**
  120. * Loads stuff after the page loads.
  121. *
  122. * @param {boolean} skipInMeetingChecks - Whether to skip in meeting checks.
  123. * @returns {Promise<void>}
  124. * @private
  125. */
  126. private async postLoadProcess(skipInMeetingChecks: boolean) {
  127. const driver = this.driver;
  128. const parallel = [];
  129. parallel.push(driver.execute((name, sessionId, prefix) => {
  130. APP.UI.dockToolbar(true);
  131. // disable keyframe animations (.fadeIn and .fadeOut classes)
  132. $('<style>.notransition * { '
  133. + 'animation-duration: 0s !important; -webkit-animation-duration: 0s !important; transition:none; '
  134. + '} </style>') // @ts-ignore
  135. .appendTo(document.head);
  136. // @ts-ignore
  137. $('body').toggleClass('notransition');
  138. document.title = `${name}`;
  139. console.log(`${new Date().toISOString()} ${prefix} sessionId: ${sessionId}`);
  140. // disable the blur effect in firefox as it has some performance issues
  141. const blur = document.querySelector('.video_blurred_container');
  142. if (blur) {
  143. // @ts-ignore
  144. document.querySelector('.video_blurred_container').style.display = 'none';
  145. }
  146. }, this._name, driver.sessionId, LOG_PREFIX));
  147. if (skipInMeetingChecks) {
  148. await Promise.allSettled(parallel);
  149. return;
  150. }
  151. parallel.push(this.waitForIceConnected());
  152. parallel.push(this.waitForSendReceiveData());
  153. await Promise.all(parallel);
  154. }
  155. /**
  156. * Waits for the page to load.
  157. *
  158. * @returns {Promise<void>}
  159. */
  160. async waitForPageToLoad() {
  161. return this.driver.waitUntil(
  162. () => this.driver.execute(() => document.readyState === 'complete'),
  163. {
  164. timeout: 30_000, // 30 seconds
  165. timeoutMsg: 'Timeout waiting for Page Load Request to complete.'
  166. }
  167. );
  168. }
  169. /**
  170. * Waits to join the muc.
  171. *
  172. * @returns {Promise<void>}
  173. */
  174. async waitToJoinMUC() {
  175. return this.driver.waitUntil(
  176. () => this.driver.execute(() => APP.conference.isJoined()),
  177. {
  178. timeout: 10_000, // 10 seconds
  179. timeoutMsg: 'Timeout waiting to join muc.'
  180. }
  181. );
  182. }
  183. /**
  184. * Waits for ICE to get connected.
  185. *
  186. * @returns {Promise<void>}
  187. */
  188. async waitForIceConnected() {
  189. const driver = this.driver;
  190. return driver.waitUntil(async () =>
  191. driver.execute(() => APP.conference.getConnectionState() === 'connected'), {
  192. timeout: 15_000,
  193. timeoutMsg: 'expected ICE to be connected for 15s'
  194. });
  195. }
  196. /**
  197. * Waits for send and receive data.
  198. *
  199. * @returns {Promise<void>}
  200. */
  201. async waitForSendReceiveData() {
  202. const driver = this.driver;
  203. return driver.waitUntil(async () =>
  204. driver.execute(() => {
  205. const stats = APP.conference.getStats();
  206. const bitrateMap = stats?.bitrate || {};
  207. const rtpStats = {
  208. uploadBitrate: bitrateMap.upload || 0,
  209. downloadBitrate: bitrateMap.download || 0
  210. };
  211. return rtpStats.uploadBitrate > 0 && rtpStats.downloadBitrate > 0;
  212. }), {
  213. timeout: 15_000,
  214. timeoutMsg: 'expected to receive/send data in 15s'
  215. });
  216. }
  217. /**
  218. * Waits for remote streams.
  219. *
  220. * @param {number} number - The number of remote streams o wait for.
  221. * @returns {Promise<void>}
  222. */
  223. waitForRemoteStreams(number: number) {
  224. const driver = this.driver;
  225. return driver.waitUntil(async () =>
  226. driver.execute(count => APP.conference.getNumberOfParticipantsWithTracks() >= count, number), {
  227. timeout: 15_000,
  228. timeoutMsg: 'expected remote streams in 15s'
  229. });
  230. }
  231. /**
  232. * Returns the toolbar for this participant.
  233. *
  234. * @returns {Toolbar}
  235. */
  236. getToolbar() {
  237. return new Toolbar(this);
  238. }
  239. /**
  240. * Returns the filmstrip for this participant.
  241. *
  242. * @returns {Filmstrip}
  243. */
  244. getFilmstrip() {
  245. return new Filmstrip(this);
  246. }
  247. }