Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

middleware.js 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. // @flow
  2. import { jitsiLocalStorage } from '@jitsi/js-utils';
  3. import { getAmplitudeIdentity } from '../analytics';
  4. import {
  5. CONFERENCE_UNIQUE_ID_SET,
  6. E2E_RTT_CHANGED,
  7. CONFERENCE_TIMESTAMP_CHANGED,
  8. getConferenceOptions,
  9. getAnalyticsRoomName
  10. } from '../base/conference';
  11. import { LIB_WILL_INIT } from '../base/lib-jitsi-meet/actionTypes';
  12. import { DOMINANT_SPEAKER_CHANGED, getLocalParticipant } from '../base/participants';
  13. import { MiddlewareRegistry } from '../base/redux';
  14. import { TRACK_ADDED, TRACK_UPDATED } from '../base/tracks';
  15. import { ADD_FACE_EXPRESSION } from '../face-landmarks/actionTypes';
  16. import RTCStats from './RTCStats';
  17. import { canSendRtcstatsData, isRtcstatsEnabled } from './functions';
  18. import logger from './logger';
  19. /**
  20. * Middleware which intercepts lib-jitsi-meet initialization and conference join in order init the
  21. * rtcstats-client.
  22. *
  23. * @param {Store} store - The redux store.
  24. * @returns {Function}
  25. */
  26. MiddlewareRegistry.register(store => next => action => {
  27. const state = store.getState();
  28. const { dispatch } = store;
  29. const config = state['features/base/config'];
  30. const { analytics, faceLandmarks } = config;
  31. switch (action.type) {
  32. case LIB_WILL_INIT: {
  33. if (isRtcstatsEnabled(state)) {
  34. // RTCStats "proxies" WebRTC functions such as GUM and RTCPeerConnection by rewriting the global
  35. // window functions. Because lib-jitsi-meet uses references to those functions that are taken on
  36. // init, we need to add these proxies before it initializes, otherwise lib-jitsi-meet will use the
  37. // original non proxy versions of these functions.
  38. try {
  39. // Default poll interval is 10000ms and standard stats will be used, if not provided in the config.
  40. const pollInterval = analytics.rtcstatsPollInterval || 10000;
  41. const useLegacy = analytics.rtcstatsUseLegacy || false;
  42. const sendSdp = analytics.rtcstatsSendSdp || false;
  43. // Initialize but don't connect to the rtcstats server wss, as it will start sending data for all
  44. // media calls made even before the conference started.
  45. RTCStats.init({
  46. endpoint: analytics.rtcstatsEndpoint,
  47. useLegacy,
  48. pollInterval,
  49. sendSdp
  50. });
  51. } catch (error) {
  52. logger.error('Failed to initialize RTCStats: ', error);
  53. }
  54. }
  55. break;
  56. }
  57. case TRACK_ADDED: {
  58. if (canSendRtcstatsData(state)) {
  59. const jitsiTrack = action?.track?.jitsiTrack;
  60. const { ssrc, videoType } = jitsiTrack || { };
  61. // Remote tracks store their ssrc in the jitsiTrack object. Local tracks don't. See getSsrcByTrack.
  62. if (videoType && ssrc && !jitsiTrack.isLocal() && !jitsiTrack.isAudioTrack()) {
  63. RTCStats.sendVideoTypeData({
  64. ssrc,
  65. videoType
  66. });
  67. }
  68. }
  69. break;
  70. }
  71. case TRACK_UPDATED: {
  72. if (canSendRtcstatsData(state)) {
  73. const { videoType, jitsiTrack } = action?.track || { };
  74. const { ssrc } = jitsiTrack || { };
  75. // if the videoType of the remote track has changed we expect to find it in track.videoType. grep for
  76. // trackVideoTypeChanged.
  77. if (videoType && ssrc && !jitsiTrack.isLocal() && !jitsiTrack.isAudioTrack()) {
  78. RTCStats.sendVideoTypeData({
  79. ssrc,
  80. videoType
  81. });
  82. }
  83. }
  84. break;
  85. }
  86. case CONFERENCE_UNIQUE_ID_SET: {
  87. if (canSendRtcstatsData(state)) {
  88. // Once the conference started connect to the rtcstats server and send data.
  89. try {
  90. RTCStats.connect();
  91. const localParticipant = getLocalParticipant(state);
  92. const options = getConferenceOptions(state);
  93. // Unique identifier for a conference session, not to be confused with meeting name
  94. // i.e. If all participants leave a meeting it will have a different value on the next join.
  95. const { conference } = action;
  96. const meetingUniqueId = conference && conference.getMeetingUniqueId();
  97. // The current implementation of rtcstats-server is configured to send data to amplitude, thus
  98. // we add identity specific information so we can correlate on the amplitude side. If amplitude is
  99. // not configured an empty object will be sent.
  100. // The current configuration of the conference is also sent as metadata to rtcstats server.
  101. // This is done in order to facilitate queries based on different conference configurations.
  102. // e.g. Find all RTCPeerConnections that connect to a specific shard or were created in a
  103. // conference with a specific version.
  104. // XXX(george): we also want to be able to correlate between rtcstats and callstats, so we're
  105. // appending the callstats user name (if it exists) to the display name.
  106. const displayName = options.statisticsId
  107. || options.statisticsDisplayName
  108. || jitsiLocalStorage.getItem('callStatsUserName');
  109. RTCStats.sendIdentityData({
  110. ...getAmplitudeIdentity(),
  111. ...options,
  112. endpointId: localParticipant?.id,
  113. confName: getAnalyticsRoomName(state, dispatch),
  114. displayName,
  115. meetingUniqueId
  116. });
  117. } catch (error) {
  118. // If the connection failed do not impact jitsi-meet just silently fail.
  119. logger.error('RTCStats connect failed with: ', error);
  120. }
  121. }
  122. break;
  123. }
  124. case DOMINANT_SPEAKER_CHANGED: {
  125. if (canSendRtcstatsData(state)) {
  126. const { id, previousSpeakers } = action.participant;
  127. RTCStats.sendDominantSpeakerData({ dominantSpeakerEndpoint: id,
  128. previousSpeakers });
  129. }
  130. break;
  131. }
  132. case E2E_RTT_CHANGED: {
  133. if (canSendRtcstatsData(state)) {
  134. const { participant, rtt } = action.e2eRtt;
  135. RTCStats.sendE2eRttData({
  136. remoteEndpointId: participant.getId(),
  137. rtt,
  138. remoteRegion: participant.getProperty('region')
  139. });
  140. }
  141. break;
  142. }
  143. case ADD_FACE_EXPRESSION: {
  144. if (canSendRtcstatsData(state) && faceLandmarks && faceLandmarks.enableRTCStats) {
  145. const { duration, faceExpression, timestamp } = action;
  146. RTCStats.sendFaceExpressionData({
  147. duration,
  148. faceLandmarks: faceExpression,
  149. timestamp
  150. });
  151. }
  152. break;
  153. }
  154. case CONFERENCE_TIMESTAMP_CHANGED: {
  155. if (canSendRtcstatsData(state)) {
  156. const conferenceTimestamp = action.conferenceTimestamp;
  157. RTCStats.sendConferenceTimestamp(conferenceTimestamp);
  158. }
  159. break;
  160. }
  161. }
  162. return next(action);
  163. });