選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

subscriber.ts 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. import _ from 'lodash';
  2. import { batch } from 'react-redux';
  3. import { IStore } from '../../app/types';
  4. import { hideNotification, showNotification } from '../../notifications/actions';
  5. import { NOTIFICATION_TIMEOUT_TYPE, RAISE_HAND_NOTIFICATION_ID } from '../../notifications/constants';
  6. import { getCurrentConference } from '../conference/functions';
  7. import { getSsrcRewritingFeatureFlag, hasBeenNotified, isNextToSpeak } from '../config/functions.any';
  8. import { VIDEO_TYPE } from '../media/constants';
  9. import StateListenerRegistry from '../redux/StateListenerRegistry';
  10. import { NOTIFIED_TO_SPEAK } from './actionTypes';
  11. import { createVirtualScreenshareParticipant, participantLeft } from './actions';
  12. import {
  13. getParticipantById,
  14. getRemoteScreensharesBasedOnPresence,
  15. getVirtualScreenshareParticipantOwnerId
  16. } from './functions';
  17. import { FakeParticipant } from './types';
  18. StateListenerRegistry.register(
  19. /* selector */ state => state['features/base/tracks'],
  20. /* listener */(tracks, store) => _updateScreenshareParticipants(store)
  21. );
  22. StateListenerRegistry.register(
  23. /* selector */ state => state['features/base/participants'].remoteVideoSources,
  24. /* listener */(remoteVideoSources, store) => getSsrcRewritingFeatureFlag(store.getState())
  25. && _updateScreenshareParticipantsBasedOnPresence(store)
  26. );
  27. StateListenerRegistry.register(
  28. /* selector */ state => state['features/base/participants'].raisedHandsQueue,
  29. /* listener */ (raisedHandsQueue, store) => {
  30. if (raisedHandsQueue.length && isNextToSpeak(store.getState()) && !hasBeenNotified(store.getState())) {
  31. _notifyNextSpeakerInRaisedHandQueue(store);
  32. }
  33. if (!raisedHandsQueue[0]) {
  34. store.dispatch(hideNotification(RAISE_HAND_NOTIFICATION_ID));
  35. }
  36. }
  37. );
  38. /**
  39. * Compares the old and new screenshare lists provided and creates/removes the virtual screenshare participant
  40. * tiles accodingly.
  41. *
  42. * @param {Array<string>} oldScreenshareSourceNames - List of old screenshare source names.
  43. * @param {Array<string>} newScreenshareSourceNames - Current list of screenshare source names.
  44. * @param {Object} store - The redux store.
  45. * @returns {void}
  46. */
  47. function _createOrRemoveVirtualParticipants(
  48. oldScreenshareSourceNames: string[],
  49. newScreenshareSourceNames: string[],
  50. store: IStore): void {
  51. const { dispatch, getState } = store;
  52. const conference = getCurrentConference(getState());
  53. const removedScreenshareSourceNames = _.difference(oldScreenshareSourceNames, newScreenshareSourceNames);
  54. const addedScreenshareSourceNames = _.difference(newScreenshareSourceNames, oldScreenshareSourceNames);
  55. if (removedScreenshareSourceNames.length) {
  56. removedScreenshareSourceNames.forEach(id => dispatch(participantLeft(id, conference, {
  57. fakeParticipant: FakeParticipant.RemoteScreenShare
  58. })));
  59. }
  60. if (addedScreenshareSourceNames.length) {
  61. addedScreenshareSourceNames.forEach(id => dispatch(
  62. createVirtualScreenshareParticipant(id, false, conference)));
  63. }
  64. }
  65. /**
  66. * Handles creating and removing virtual screenshare participants.
  67. *
  68. * @param {*} store - The redux store.
  69. * @returns {void}
  70. */
  71. function _updateScreenshareParticipants(store: IStore): void {
  72. const { dispatch, getState } = store;
  73. const state = getState();
  74. const conference = getCurrentConference(state);
  75. const tracks = state['features/base/tracks'];
  76. const { sortedRemoteVirtualScreenshareParticipants, localScreenShare } = state['features/base/participants'];
  77. const previousScreenshareSourceNames = [ ...sortedRemoteVirtualScreenshareParticipants.keys() ];
  78. let newLocalSceenshareSourceName;
  79. const currentScreenshareSourceNames = tracks.reduce((acc: string[], track) => {
  80. if (track.videoType === VIDEO_TYPE.DESKTOP && !track.jitsiTrack.isMuted()) {
  81. const sourceName: string = track.jitsiTrack.getSourceName();
  82. // Ignore orphan tracks in ssrc-rewriting mode.
  83. if (!sourceName && getSsrcRewritingFeatureFlag(state)) {
  84. return acc;
  85. }
  86. if (track.local) {
  87. newLocalSceenshareSourceName = sourceName;
  88. } else if (getParticipantById(state, getVirtualScreenshareParticipantOwnerId(sourceName))) {
  89. acc.push(sourceName);
  90. }
  91. }
  92. return acc;
  93. }, []);
  94. if (!localScreenShare && newLocalSceenshareSourceName) {
  95. dispatch(createVirtualScreenshareParticipant(newLocalSceenshareSourceName, true, conference));
  96. }
  97. if (localScreenShare && !newLocalSceenshareSourceName) {
  98. dispatch(participantLeft(localScreenShare.id, conference, {
  99. fakeParticipant: FakeParticipant.LocalScreenShare
  100. }));
  101. }
  102. if (getSsrcRewritingFeatureFlag(state)) {
  103. return;
  104. }
  105. _createOrRemoveVirtualParticipants(previousScreenshareSourceNames, currentScreenshareSourceNames, store);
  106. }
  107. /**
  108. * Handles the creation and removal of remote virtual screenshare participants when ssrc-rewriting is enabled.
  109. *
  110. * @param {Object} store - The redux store.
  111. * @returns {void}
  112. */
  113. function _updateScreenshareParticipantsBasedOnPresence(store: IStore): void {
  114. const { getState } = store;
  115. const state = getState();
  116. const { sortedRemoteVirtualScreenshareParticipants } = state['features/base/participants'];
  117. const previousScreenshareSourceNames = [ ...sortedRemoteVirtualScreenshareParticipants.keys() ];
  118. const currentScreenshareSourceNames = getRemoteScreensharesBasedOnPresence(state);
  119. _createOrRemoveVirtualParticipants(previousScreenshareSourceNames, currentScreenshareSourceNames, store);
  120. }
  121. /**
  122. * Handles notifying the next speaker in the raised hand queue.
  123. *
  124. * @param {*} store - The redux store.
  125. * @returns {void}
  126. */
  127. function _notifyNextSpeakerInRaisedHandQueue(store: IStore): void {
  128. const { dispatch } = store;
  129. batch(() => {
  130. dispatch(showNotification({
  131. titleKey: 'notify.nextToSpeak',
  132. maxLines: 2
  133. }, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
  134. dispatch({
  135. type: NOTIFIED_TO_SPEAK
  136. });
  137. });
  138. }