您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

load-test-participant.js 9.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. /* global $, config, JitsiMeetJS */
  2. import 'jquery';
  3. import { setConfigFromURLParams } from '../../react/features/base/config/functions';
  4. import { parseURLParams } from '../../react/features/base/util/parseURLParams';
  5. import { parseURIString } from '../../react/features/base/util/uri';
  6. import { validateLastNLimits, limitLastN } from '../../react/features/base/lastn/functions';
  7. setConfigFromURLParams(config, {}, {}, window.location);
  8. const params = parseURLParams(window.location, false, 'hash');
  9. const { isHuman = false } = params;
  10. const {
  11. localVideo = config.startWithVideoMuted !== true,
  12. remoteVideo = isHuman,
  13. remoteAudio = isHuman,
  14. autoPlayVideo = config.testing.noAutoPlayVideo !== true,
  15. } = params;
  16. let {
  17. localAudio = config.startWithAudioMuted !== true,
  18. } = params;
  19. const { room: roomName } = parseURIString(window.location.toString());
  20. let connection = null;
  21. let connected = false;
  22. let room = null;
  23. let numParticipants = 1;
  24. let localTracks = [];
  25. const remoteTracks = {};
  26. let maxFrameHeight = 0;
  27. window.APP = {
  28. conference: {
  29. getStats() {
  30. return room.connectionQuality.getStats();
  31. },
  32. getConnectionState() {
  33. return room && room.getConnectionState();
  34. },
  35. muteAudio(mute) {
  36. localAudio = mute;
  37. for (let i = 0; i < localTracks.length; i++) {
  38. if (localTracks[i].getType() === 'audio') {
  39. if (mute) {
  40. localTracks[i].mute();
  41. }
  42. else {
  43. localTracks[i].unmute();
  44. // if track was not added we need to add it to the peerconnection
  45. if (!room.getLocalAudioTrack()) {
  46. room.replaceTrack(null, localTracks[i]);
  47. }
  48. }
  49. }
  50. }
  51. }
  52. },
  53. get room() {
  54. return room;
  55. },
  56. get connection() {
  57. return connection;
  58. },
  59. get numParticipants() {
  60. return numParticipants;
  61. },
  62. get localTracks() {
  63. return localTracks;
  64. },
  65. get remoteTracks() {
  66. return remoteTracks;
  67. },
  68. get params() {
  69. return {
  70. roomName,
  71. localAudio,
  72. localVideo,
  73. remoteVideo,
  74. remoteAudio,
  75. autoPlayVideo
  76. };
  77. }
  78. };
  79. /**
  80. * Simple emulation of jitsi-meet's screen layout behavior
  81. */
  82. function updateMaxFrameHeight() {
  83. if (!connected) {
  84. return;
  85. }
  86. let newMaxFrameHeight;
  87. if (numParticipants <= 2) {
  88. newMaxFrameHeight = 720;
  89. } else if (numParticipants <= 4) {
  90. newMaxFrameHeight = 360;
  91. } else {
  92. newMaxFrameHeight = 180;
  93. }
  94. if (room && maxFrameHeight !== newMaxFrameHeight) {
  95. maxFrameHeight = newMaxFrameHeight;
  96. room.setReceiverVideoConstraint(maxFrameHeight);
  97. }
  98. }
  99. /**
  100. * Simple emulation of jitsi-meet's lastN behavior
  101. */
  102. function updateLastN() {
  103. if (!connected) {
  104. return;
  105. }
  106. let lastN = typeof config.channelLastN === 'undefined' ? -1 : config.channelLastN;
  107. const limitedLastN = limitLastN(numParticipants, validateLastNLimits(config.lastNLimits));
  108. if (limitedLastN !== undefined) {
  109. lastN = lastN === -1 ? limitedLastN : Math.min(limitedLastN, lastN);
  110. }
  111. if (lastN === room.getLastN()) {
  112. return;
  113. }
  114. room.setLastN(lastN);
  115. }
  116. /**
  117. * Simple emulation of jitsi-meet's selectParticipants behavior
  118. */
  119. function selectParticipants() {
  120. if (!connected) {
  121. return;
  122. }
  123. /* jitsi-meet's current Tile View behavior. */
  124. const ids = room.getParticipants().map(participant => participant.getId());
  125. room.selectParticipants(ids);
  126. }
  127. /**
  128. * Called when number of participants changes.
  129. */
  130. function setNumberOfParticipants() {
  131. $('#participants').text(numParticipants);
  132. selectParticipants();
  133. updateMaxFrameHeight();
  134. updateLastN();
  135. }
  136. /**
  137. * Called when ICE connects
  138. */
  139. function onConnectionEstablished() {
  140. connected = true;
  141. selectParticipants();
  142. updateMaxFrameHeight();
  143. updateLastN();
  144. }
  145. /**
  146. * Handles local tracks.
  147. * @param tracks Array with JitsiTrack objects
  148. */
  149. function onLocalTracks(tracks = []) {
  150. localTracks = tracks;
  151. for (let i = 0; i < localTracks.length; i++) {
  152. if (localTracks[i].getType() === 'video') {
  153. $('body').append(`<video ${autoPlayVideo ? 'autoplay="1" ' : ''}id='localVideo${i}' />`);
  154. localTracks[i].attach($(`#localVideo${i}`)[0]);
  155. room.addTrack(localTracks[i]);
  156. } else {
  157. if (localAudio) {
  158. room.addTrack(localTracks[i]);
  159. } else {
  160. localTracks[i].mute();
  161. }
  162. $('body').append(
  163. `<audio autoplay='1' muted='true' id='localAudio${i}' />`);
  164. localTracks[i].attach($(`#localAudio${i}`)[0]);
  165. }
  166. }
  167. }
  168. /**
  169. * Handles remote tracks
  170. * @param track JitsiTrack object
  171. */
  172. function onRemoteTrack(track) {
  173. if (track.isLocal()
  174. || (track.getType() === 'video' && !remoteVideo) || (track.getType() === 'audio' && !remoteAudio)) {
  175. return;
  176. }
  177. const participant = track.getParticipantId();
  178. if (!remoteTracks[participant]) {
  179. remoteTracks[participant] = [];
  180. }
  181. const idx = remoteTracks[participant].push(track);
  182. const id = participant + track.getType() + idx;
  183. if (track.getType() === 'video') {
  184. $('body').append(`<video autoplay='1' id='${id}' />`);
  185. } else {
  186. $('body').append(`<audio autoplay='1' id='${id}' />`);
  187. }
  188. track.attach($(`#${id}`)[0]);
  189. }
  190. /**
  191. * That function is executed when the conference is joined
  192. */
  193. function onConferenceJoined() {
  194. console.log('Conference joined');
  195. }
  196. /**
  197. * Handles start muted events, when audio and/or video are muted due to
  198. * startAudioMuted or startVideoMuted policy.
  199. */
  200. function onStartMuted() {
  201. // Give it some time, as it may be currently in the process of muting
  202. setTimeout(() => {
  203. const localAudioTrack = room.getLocalAudioTrack();
  204. if (localAudio && localAudioTrack && localAudioTrack.isMuted()) {
  205. localAudioTrack.unmute();
  206. }
  207. const localVideoTrack = room.getLocalVideoTrack();
  208. if (localVideo && localVideoTrack && localVideoTrack.isMuted()) {
  209. localVideoTrack.unmute();
  210. }
  211. }, 2000);
  212. }
  213. /**
  214. *
  215. * @param id
  216. */
  217. function onUserJoined(id) {
  218. numParticipants++;
  219. setNumberOfParticipants();
  220. remoteTracks[id] = [];
  221. }
  222. /**
  223. *
  224. * @param id
  225. */
  226. function onUserLeft(id) {
  227. numParticipants--;
  228. setNumberOfParticipants();
  229. if (!remoteTracks[id]) {
  230. return;
  231. }
  232. const tracks = remoteTracks[id];
  233. for (let i = 0; i < tracks.length; i++) {
  234. const container = $(`#${id}${tracks[i].getType()}${i + 1}`)[0];
  235. if (container) {
  236. tracks[i].detach(container);
  237. container.parentElement.removeChild(container);
  238. }
  239. }
  240. }
  241. /**
  242. * That function is called when connection is established successfully
  243. */
  244. function onConnectionSuccess() {
  245. room = connection.initJitsiConference(roomName.toLowerCase(), config);
  246. room.on(JitsiMeetJS.events.conference.STARTED_MUTED, onStartMuted);
  247. room.on(JitsiMeetJS.events.conference.TRACK_ADDED, onRemoteTrack);
  248. room.on(JitsiMeetJS.events.conference.CONFERENCE_JOINED, onConferenceJoined);
  249. room.on(JitsiMeetJS.events.conference.CONNECTION_ESTABLISHED, onConnectionEstablished);
  250. room.on(JitsiMeetJS.events.conference.USER_JOINED, onUserJoined);
  251. room.on(JitsiMeetJS.events.conference.USER_LEFT, onUserLeft);
  252. const devices = [];
  253. if (localVideo) {
  254. devices.push('video');
  255. }
  256. // we always create audio local tracks
  257. devices.push('audio');
  258. if (devices.length > 0) {
  259. JitsiMeetJS.createLocalTracks({ devices })
  260. .then(onLocalTracks)
  261. .then(() => {
  262. room.join();
  263. })
  264. .catch(error => {
  265. throw error;
  266. });
  267. } else {
  268. room.join();
  269. }
  270. updateMaxFrameHeight();
  271. }
  272. /**
  273. * This function is called when the connection fail.
  274. */
  275. function onConnectionFailed() {
  276. console.error('Connection Failed!');
  277. }
  278. /**
  279. * This function is called when we disconnect.
  280. */
  281. function disconnect() {
  282. console.log('disconnect!');
  283. connection.removeEventListener(
  284. JitsiMeetJS.events.connection.CONNECTION_ESTABLISHED,
  285. onConnectionSuccess);
  286. connection.removeEventListener(
  287. JitsiMeetJS.events.connection.CONNECTION_FAILED,
  288. onConnectionFailed);
  289. connection.removeEventListener(
  290. JitsiMeetJS.events.connection.CONNECTION_DISCONNECTED,
  291. disconnect);
  292. }
  293. /**
  294. *
  295. */
  296. function unload() {
  297. for (let i = 0; i < localTracks.length; i++) {
  298. localTracks[i].dispose();
  299. }
  300. room.leave();
  301. connection.disconnect();
  302. }
  303. $(window).bind('beforeunload', unload);
  304. $(window).bind('unload', unload);
  305. JitsiMeetJS.setLogLevel(JitsiMeetJS.logLevels.ERROR);
  306. JitsiMeetJS.init(config);
  307. config.serviceUrl = config.bosh = `${config.websocket || config.bosh}?room=${roomName.toLowerCase()}`;
  308. if (config.websocketKeepAliveUrl) {
  309. config.websocketKeepAliveUrl += `?room=${roomName.toLowerCase()}`;
  310. }
  311. connection = new JitsiMeetJS.JitsiConnection(null, null, config);
  312. connection.addEventListener(JitsiMeetJS.events.connection.CONNECTION_ESTABLISHED, onConnectionSuccess);
  313. connection.addEventListener(JitsiMeetJS.events.connection.CONNECTION_FAILED, onConnectionFailed);
  314. connection.addEventListener(JitsiMeetJS.events.connection.CONNECTION_DISCONNECTED, disconnect);
  315. connection.connect();