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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. import { MediaType } from '../media/constants';
  2. import { PARTICIPANT_ID_CHANGED } from '../participants/actionTypes';
  3. import ReducerRegistry from '../redux/ReducerRegistry';
  4. import { set } from '../redux/functions';
  5. import {
  6. SET_NO_SRC_DATA_NOTIFICATION_UID,
  7. TRACK_ADDED,
  8. TRACK_CREATE_CANCELED,
  9. TRACK_CREATE_ERROR,
  10. TRACK_NO_DATA_FROM_SOURCE,
  11. TRACK_REMOVED,
  12. TRACK_UPDATED,
  13. TRACK_UPDATE_LAST_VIDEO_MEDIA_EVENT,
  14. TRACK_WILL_CREATE
  15. } from './actionTypes';
  16. export interface ITrack {
  17. isReceivingData: boolean;
  18. jitsiTrack: any;
  19. lastMediaEvent?: string;
  20. local: boolean;
  21. mediaType: MediaType;
  22. mirror: boolean;
  23. muted: boolean;
  24. noDataFromSourceNotificationInfo?: {
  25. timeout?: number;
  26. uid?: string;
  27. };
  28. participantId: string;
  29. streamingStatus?: string;
  30. videoStarted: boolean;
  31. videoType?: string | null;
  32. }
  33. /**
  34. * Track type.
  35. *
  36. * @typedef {object} Track
  37. * @property {JitsiLocalTrack|JitsiRemoteTrack} jitsiTrack - The associated
  38. * {@code JitsiTrack} instance. Optional for local tracks if those are still
  39. * being created (ie {@code getUserMedia} is still in progress).
  40. * @property {Promise} [gumProcess] - If a local track is still being created,
  41. * it will have no {@code JitsiTrack}, but a {@code gumProcess} set to a
  42. * {@code Promise} with and extra {@code cancel()}.
  43. * @property {boolean} local=false - If the track is local.
  44. * @property {MEDIA_TYPE} mediaType=false - The media type of the track.
  45. * @property {boolean} mirror=false - The indicator which determines whether the
  46. * display/rendering of the track should be mirrored. It only makes sense in the
  47. * context of video (at least at the time of this writing).
  48. * @property {boolean} muted=false - If the track is muted.
  49. * @property {(string|undefined)} participantId - The ID of the participant whom
  50. * the track belongs to.
  51. * @property {boolean} videoStarted=false - If the video track has already
  52. * started to play.
  53. * @property {(VIDEO_TYPE|undefined)} videoType - The type of video track if
  54. * any.
  55. */
  56. /**
  57. * Reducer function for a single track.
  58. *
  59. * @param {Track|undefined} state - Track to be modified.
  60. * @param {Object} action - Action object.
  61. * @param {string} action.type - Type of action.
  62. * @param {string} action.name - Name of last media event.
  63. * @param {string} action.newValue - New participant ID value (in this
  64. * particular case).
  65. * @param {string} action.oldValue - Old participant ID value (in this
  66. * particular case).
  67. * @param {Track} action.track - Information about track to be changed.
  68. * @param {Participant} action.participant - Information about participant.
  69. * @returns {Track|undefined}
  70. */
  71. function track(state: ITrack, action: any) {
  72. switch (action.type) {
  73. case PARTICIPANT_ID_CHANGED:
  74. if (state.participantId === action.oldValue) {
  75. return {
  76. ...state,
  77. participantId: action.newValue
  78. };
  79. }
  80. break;
  81. case TRACK_UPDATED: {
  82. const t = action.track;
  83. if (state.jitsiTrack === t.jitsiTrack) {
  84. // Make sure that there's an actual update in order to reduce the
  85. // risk of unnecessary React Component renders.
  86. for (const p in t) {
  87. // @ts-ignore
  88. if (state[p] !== t[p]) {
  89. // There's an actual update.
  90. return {
  91. ...state,
  92. ...t
  93. };
  94. }
  95. }
  96. }
  97. break;
  98. }
  99. case TRACK_UPDATE_LAST_VIDEO_MEDIA_EVENT: {
  100. const t = action.track;
  101. if (state.jitsiTrack === t) {
  102. if (state.lastMediaEvent !== action.name) {
  103. return {
  104. ...state,
  105. lastMediaEvent: action.name
  106. };
  107. }
  108. }
  109. break;
  110. }
  111. case TRACK_NO_DATA_FROM_SOURCE: {
  112. const t = action.track;
  113. if (state.jitsiTrack === t.jitsiTrack) {
  114. const isReceivingData = t.jitsiTrack.isReceivingData();
  115. if (state.isReceivingData !== isReceivingData) {
  116. return {
  117. ...state,
  118. isReceivingData
  119. };
  120. }
  121. }
  122. break;
  123. }
  124. }
  125. return state;
  126. }
  127. export type ITracksState = ITrack[];
  128. /**
  129. * Listen for actions that mutate (e.g. Add, remove) local and remote tracks.
  130. */
  131. ReducerRegistry.register<ITracksState>('features/base/tracks', (state = [], action): ITracksState => {
  132. switch (action.type) {
  133. case PARTICIPANT_ID_CHANGED:
  134. case TRACK_NO_DATA_FROM_SOURCE:
  135. case TRACK_UPDATE_LAST_VIDEO_MEDIA_EVENT:
  136. case TRACK_UPDATED:
  137. return state.map((t: ITrack) => track(t, action));
  138. case TRACK_ADDED: {
  139. let withoutTrackStub = state;
  140. if (action.track.local) {
  141. withoutTrackStub
  142. = state.filter(
  143. (t: ITrack) => !t.local || t.mediaType !== action.track.mediaType);
  144. }
  145. return [ ...withoutTrackStub, action.track ];
  146. }
  147. case TRACK_CREATE_CANCELED:
  148. case TRACK_CREATE_ERROR: {
  149. return state.filter((t: ITrack) => !t.local || t.mediaType !== action.trackType);
  150. }
  151. case TRACK_REMOVED:
  152. return state.filter((t: ITrack) => t.jitsiTrack !== action.track.jitsiTrack);
  153. case TRACK_WILL_CREATE:
  154. return [ ...state, action.track ];
  155. default:
  156. return state;
  157. }
  158. });
  159. export interface INoSrcDataState {
  160. noSrcDataNotificationUid?: string | number;
  161. }
  162. /**
  163. * Listen for actions that mutate the no-src-data state, like the current notification id.
  164. */
  165. ReducerRegistry.register<INoSrcDataState>('features/base/no-src-data', (state = {}, action): INoSrcDataState => {
  166. switch (action.type) {
  167. case SET_NO_SRC_DATA_NOTIFICATION_UID:
  168. return set(state, 'noSrcDataNotificationUid', action.uid);
  169. default:
  170. return state;
  171. }
  172. });