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.

middleware.js 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. // @flow
  2. import {
  3. CONFERENCE_JOINED,
  4. CONFERENCE_WILL_LEAVE,
  5. SET_ROOM
  6. } from '../base/conference';
  7. import { SET_CONFIG } from '../base/config';
  8. import { SET_NETWORK_INFO } from '../base/net-info';
  9. import { MiddlewareRegistry } from '../base/redux';
  10. import {
  11. getLocalAudioTrack,
  12. getLocalVideoTrack,
  13. TRACK_ADDED,
  14. TRACK_REMOVED,
  15. TRACK_UPDATED
  16. } from '../base/tracks';
  17. import { UPDATE_LOCAL_TRACKS_DURATION } from './actionTypes';
  18. import { createLocalTracksDurationEvent, createNetworkInfoEvent } from './AnalyticsEvents';
  19. import { createHandlers, initAnalytics, resetAnalytics, sendAnalytics } from './functions';
  20. /**
  21. * Calculates the duration of the local tracks.
  22. *
  23. * @param {Object} state - The redux state.
  24. * @returns {Object} - The local tracks duration.
  25. */
  26. function calculateLocalTrackDuration(state) {
  27. const now = Date.now();
  28. const { localTracksDuration } = state['features/analytics'];
  29. const { conference } = state['features/base/conference'];
  30. const { audio, video } = localTracksDuration;
  31. const { camera, desktop } = video;
  32. const tracks = state['features/base/tracks'];
  33. const audioTrack = getLocalAudioTrack(tracks);
  34. const videoTrack = getLocalVideoTrack(tracks);
  35. const newDuration = { ...localTracksDuration };
  36. if (!audioTrack || audioTrack.muted || !conference) {
  37. newDuration.audio = {
  38. startedTime: -1,
  39. value: audio.value + (audio.startedTime === -1 ? 0 : now - audio.startedTime)
  40. };
  41. } else if (audio.startedTime === -1) {
  42. newDuration.audio.startedTime = now;
  43. }
  44. if (!videoTrack || videoTrack.muted || !conference) {
  45. newDuration.video = {
  46. camera: {
  47. startedTime: -1,
  48. value: camera.value + (camera.startedTime === -1 ? 0 : now - camera.startedTime)
  49. },
  50. desktop: {
  51. startedTime: -1,
  52. value: desktop.value + (desktop.startedTime === -1 ? 0 : now - desktop.startedTime)
  53. }
  54. };
  55. } else {
  56. const { videoType } = videoTrack;
  57. if (video[videoType].startedTime === -1) {
  58. newDuration.video[videoType].startedTime = now;
  59. }
  60. }
  61. return {
  62. ...localTracksDuration,
  63. ...newDuration
  64. };
  65. }
  66. /**
  67. * Middleware which intercepts config actions to handle evaluating analytics
  68. * config based on the config stored in the store.
  69. *
  70. * @param {Store} store - The redux store.
  71. * @returns {Function}
  72. */
  73. MiddlewareRegistry.register(store => next => action => {
  74. switch (action.type) {
  75. case SET_CONFIG:
  76. if (navigator.product === 'ReactNative') {
  77. // Reseting the analytics is currently not needed for web because
  78. // the user will be redirected to another page and new instance of
  79. // Analytics will be created and initialized.
  80. resetAnalytics();
  81. }
  82. break;
  83. case SET_ROOM: {
  84. // createHandlers is called before the SET_ROOM action is executed in order for Amplitude to initialize before
  85. // the deeplinking logic is executed (after the SET_ROOM action) so that the Amplitude device id is available
  86. // if needed.
  87. const createHandlersPromise = createHandlers(store);
  88. const result = next(action);
  89. createHandlersPromise.then(handlers => {
  90. initAnalytics(store, handlers);
  91. });
  92. return result;
  93. }
  94. }
  95. const result = next(action);
  96. switch (action.type) {
  97. case CONFERENCE_JOINED: {
  98. const { dispatch, getState } = store;
  99. const state = getState();
  100. dispatch({
  101. type: UPDATE_LOCAL_TRACKS_DURATION,
  102. localTracksDuration: {
  103. ...calculateLocalTrackDuration(state),
  104. conference: {
  105. startedTime: Date.now(),
  106. value: 0
  107. }
  108. }
  109. });
  110. break;
  111. }
  112. case CONFERENCE_WILL_LEAVE: {
  113. const { dispatch, getState } = store;
  114. const state = getState();
  115. const { localTracksDuration } = state['features/analytics'];
  116. const newLocalTracksDuration = {
  117. ...calculateLocalTrackDuration(state),
  118. conference: {
  119. startedTime: -1,
  120. value: Date.now() - localTracksDuration.conference.startedTime
  121. }
  122. };
  123. sendAnalytics(createLocalTracksDurationEvent(newLocalTracksDuration));
  124. dispatch({
  125. type: UPDATE_LOCAL_TRACKS_DURATION,
  126. localTracksDuration: newLocalTracksDuration
  127. });
  128. break;
  129. }
  130. case SET_NETWORK_INFO:
  131. sendAnalytics(
  132. createNetworkInfoEvent({
  133. isOnline: action.isOnline,
  134. details: action.details,
  135. networkType: action.networkType
  136. }));
  137. break;
  138. case TRACK_ADDED:
  139. case TRACK_REMOVED:
  140. case TRACK_UPDATED: {
  141. const { dispatch, getState } = store;
  142. const state = getState();
  143. const { localTracksDuration } = state['features/analytics'];
  144. if (localTracksDuration.conference.startedTime === -1 || action.mediaType === 'presenter') {
  145. // We don't want to track the media duration if the conference is not joined yet because otherwise we won't
  146. // be able to compare them with the conference duration (from conference join to conference will leave).
  147. // Also, do not track media duration for presenter tracks.
  148. break;
  149. }
  150. dispatch({
  151. type: UPDATE_LOCAL_TRACKS_DURATION,
  152. localTracksDuration: {
  153. ...localTracksDuration,
  154. ...calculateLocalTrackDuration(state)
  155. }
  156. });
  157. break;
  158. }
  159. }
  160. return result;
  161. });