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.

actions.any.js 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // @flow
  2. import type { Dispatch } from 'redux';
  3. import { MEDIA_TYPE } from '../base/media';
  4. import { getParticipants } from '../base/participants';
  5. import { selectEndpoints, shouldDisplayTileView } from '../video-layout';
  6. import {
  7. SELECT_LARGE_VIDEO_PARTICIPANT,
  8. UPDATE_KNOWN_LARGE_VIDEO_RESOLUTION
  9. } from './actionTypes';
  10. /**
  11. * Signals conference to select a participant.
  12. *
  13. * @returns {Function}
  14. */
  15. export function selectParticipant() {
  16. return (dispatch: Dispatch<any>, getState: Function) => {
  17. const state = getState();
  18. const ids = shouldDisplayTileView(state)
  19. ? getParticipants(state).map(participant => participant.id)
  20. : [ state['features/large-video'].participantId ];
  21. dispatch(selectEndpoints(ids));
  22. };
  23. }
  24. /**
  25. * Action to select the participant to be displayed in LargeVideo based on the
  26. * participant id provided. If a participant id is not provided, the LargeVideo
  27. * participant will be selected based on a variety of factors: If there is a
  28. * dominant or pinned speaker, or if there are remote tracks, etc.
  29. *
  30. * @param {string} participant - The participant id of the user that needs to be
  31. * displayed on the large video.
  32. * @returns {Function}
  33. */
  34. export function selectParticipantInLargeVideo(participant: ?string) {
  35. return (dispatch: Dispatch<any>, getState: Function) => {
  36. const state = getState();
  37. const participantId = participant ?? _electParticipantInLargeVideo(state);
  38. const largeVideo = state['features/large-video'];
  39. const remoteScreenShares = state['features/video-layout'].remoteScreenShares;
  40. let latestScreenshareParticipantId;
  41. if (remoteScreenShares && remoteScreenShares.length) {
  42. latestScreenshareParticipantId = remoteScreenShares[remoteScreenShares.length - 1];
  43. }
  44. // When trying to auto pin screenshare, always select the endpoint even though it happens to be
  45. // the large video participant in redux (for the reasons listed above in the large video selection
  46. // logic above). The auto pin screenshare logic kicks in after the track is added
  47. // (which updates the large video participant and selects all endpoints because of the auto tile
  48. // view mode). If the screenshare endpoint is not among the forwarded endpoints from the bridge,
  49. // it needs to be selected again at this point.
  50. if (participantId !== largeVideo.participantId || participantId === latestScreenshareParticipantId) {
  51. dispatch({
  52. type: SELECT_LARGE_VIDEO_PARTICIPANT,
  53. participantId
  54. });
  55. dispatch(selectParticipant());
  56. }
  57. };
  58. }
  59. /**
  60. * Updates the currently seen resolution of the video displayed on large video.
  61. *
  62. * @param {number} resolution - The current resolution (height) of the video.
  63. * @returns {{
  64. * type: UPDATE_KNOWN_LARGE_VIDEO_RESOLUTION,
  65. * resolution: number
  66. * }}
  67. */
  68. export function updateKnownLargeVideoResolution(resolution: number) {
  69. return {
  70. type: UPDATE_KNOWN_LARGE_VIDEO_RESOLUTION,
  71. resolution
  72. };
  73. }
  74. /**
  75. * Returns the most recent existing remote video track.
  76. *
  77. * @param {Track[]} tracks - All current tracks.
  78. * @private
  79. * @returns {(Track|undefined)}
  80. */
  81. function _electLastVisibleRemoteVideo(tracks) {
  82. // First we try to get most recent remote video track.
  83. for (let i = tracks.length - 1; i >= 0; --i) {
  84. const track = tracks[i];
  85. if (!track.local && track.mediaType === MEDIA_TYPE.VIDEO) {
  86. return track;
  87. }
  88. }
  89. }
  90. /**
  91. * Returns the identifier of the participant who is to be on the stage and
  92. * should be displayed in {@code LargeVideo}.
  93. *
  94. * @param {Object} state - The Redux state from which the participant to be
  95. * displayed in {@code LargeVideo} is to be elected.
  96. * @private
  97. * @returns {(string|undefined)}
  98. */
  99. function _electParticipantInLargeVideo(state) {
  100. // 1. If a participant is pinned, they will be shown in the LargeVideo
  101. // (regardless of whether they are local or remote).
  102. const participants = state['features/base/participants'];
  103. let participant = participants.find(p => p.pinned);
  104. if (participant) {
  105. return participant.id;
  106. }
  107. // 2. Next, pick the most recent remote screenshare that was added to the conference.
  108. const remoteScreenShares = state['features/video-layout'].remoteScreenShares;
  109. if (remoteScreenShares?.length) {
  110. return remoteScreenShares[remoteScreenShares.length - 1];
  111. }
  112. // 3. Next, pick the dominant speaker (other than self).
  113. participant = participants.find(p => p.dominantSpeaker && !p.local);
  114. if (participant) {
  115. return participant.id;
  116. }
  117. // 4. Next, pick the most recent participant with video.
  118. const tracks = state['features/base/tracks'];
  119. const videoTrack = _electLastVisibleRemoteVideo(tracks);
  120. if (videoTrack) {
  121. return videoTrack.participantId;
  122. }
  123. // 5. As a last resort, select the participant that joined last (other than poltergist or other bot type
  124. // participants).
  125. for (let i = participants.length; i > 0 && !participant; i--) {
  126. const p = participants[i - 1];
  127. !p.botType && (participant = p);
  128. }
  129. if (participant) {
  130. return participant.id;
  131. }
  132. return participants.find(p => p.local)?.id;
  133. }