您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

middleware.js 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. // @flow
  2. import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app';
  3. import { CONFERENCE_JOINED } from '../base/conference';
  4. import {
  5. formatDeviceLabel,
  6. setAudioInputDevice
  7. } from '../base/devices';
  8. import JitsiMeetJS, { JitsiConferenceEvents } from '../base/lib-jitsi-meet';
  9. import { MiddlewareRegistry } from '../base/redux';
  10. import { updateSettings } from '../base/settings';
  11. import { playSound, registerSound, unregisterSound } from '../base/sounds';
  12. import { hideNotification, showNotification } from '../notifications';
  13. import { setNoAudioSignalNotificationUid } from './actions';
  14. import { NO_AUDIO_SIGNAL_SOUND_ID } from './constants';
  15. import { NO_AUDIO_SIGNAL_SOUND_FILE } from './sounds';
  16. MiddlewareRegistry.register(store => next => async action => {
  17. const result = next(action);
  18. const { dispatch } = store;
  19. switch (action.type) {
  20. case APP_WILL_MOUNT:
  21. dispatch(registerSound(NO_AUDIO_SIGNAL_SOUND_ID, NO_AUDIO_SIGNAL_SOUND_FILE));
  22. break;
  23. case APP_WILL_UNMOUNT:
  24. dispatch(unregisterSound(NO_AUDIO_SIGNAL_SOUND_ID));
  25. break;
  26. case CONFERENCE_JOINED:
  27. _handleNoAudioSignalNotification(store, action);
  28. break;
  29. }
  30. return result;
  31. });
  32. /**
  33. * Handles the logic of displaying the no audio input detected notification as well as finding a valid device on the
  34. * system.
  35. *
  36. * @param {Store} store - The redux store in which the specified action is being dispatched.
  37. * @param {Action} action - The redux action {@code CONFERENCE_JOINED} which is being dispatched in the specified redux
  38. * store.
  39. * @private
  40. * @returns {void}
  41. */
  42. async function _handleNoAudioSignalNotification({ dispatch, getState }, action) {
  43. const { conference } = action;
  44. let confAudioInputState;
  45. conference.on(JitsiConferenceEvents.AUDIO_INPUT_STATE_CHANGE, hasAudioInput => {
  46. const { noAudioSignalNotificationUid } = getState()['features/no-audio-signal'];
  47. confAudioInputState = hasAudioInput;
  48. // In case the notification is displayed but the conference detected audio input signal we hide it.
  49. if (noAudioSignalNotificationUid && hasAudioInput) {
  50. dispatch(hideNotification(noAudioSignalNotificationUid));
  51. dispatch(setNoAudioSignalNotificationUid());
  52. }
  53. });
  54. conference.on(JitsiConferenceEvents.NO_AUDIO_INPUT, async () => {
  55. const { noSrcDataNotificationUid } = getState()['features/base/no-src-data'];
  56. // In case the 'no data detected from source' notification was already shown, we prevent the
  57. // no audio signal notification as it's redundant i.e. it's clear that the users microphone is
  58. // muted from system settings.
  59. if (noSrcDataNotificationUid) {
  60. return;
  61. }
  62. // Force the flag to false in case AUDIO_INPUT_STATE_CHANGE is received after the notification is displayed,
  63. // possibly preventing the notification from displaying because of an outdated state.
  64. confAudioInputState = false;
  65. const activeDevice = await JitsiMeetJS.getActiveAudioDevice();
  66. if (confAudioInputState) {
  67. return;
  68. }
  69. // In case there is a previous notification displayed just hide it.
  70. const { noAudioSignalNotificationUid } = getState()['features/no-audio-signal'];
  71. if (noAudioSignalNotificationUid) {
  72. dispatch(hideNotification(noAudioSignalNotificationUid));
  73. dispatch(setNoAudioSignalNotificationUid());
  74. }
  75. let descriptionKey = 'toolbar.noAudioSignalDesc';
  76. let customActionNameKey;
  77. let customActionHandler;
  78. // In case the detector picked up a device show a notification with a device suggestion
  79. if (activeDevice.deviceLabel !== '') {
  80. descriptionKey = 'toolbar.noAudioSignalDescSuggestion';
  81. // Preferably the label should be passed as an argument paired with a i18next string, however
  82. // at the point of the implementation the showNotification function only supports doing that for
  83. // the description.
  84. // TODO Add support for arguments to showNotification title and customAction strings.
  85. customActionNameKey = `Use ${formatDeviceLabel(activeDevice.deviceLabel)}`;
  86. customActionHandler = () => {
  87. // Select device callback
  88. dispatch(
  89. updateSettings({
  90. userSelectedMicDeviceId: activeDevice.deviceId,
  91. userSelectedMicDeviceLabel: activeDevice.deviceLabel
  92. })
  93. );
  94. dispatch(setAudioInputDevice(activeDevice.deviceId));
  95. };
  96. }
  97. const notification = showNotification({
  98. titleKey: 'toolbar.noAudioSignalTitle',
  99. descriptionKey,
  100. customActionNameKey,
  101. customActionHandler
  102. });
  103. dispatch(notification);
  104. dispatch(playSound(NO_AUDIO_SIGNAL_SOUND_ID));
  105. // Store the current notification uid so we can check for this state and hide it in case
  106. // a new track was added, thus changing the context of the notification
  107. dispatch(setNoAudioSignalNotificationUid(notification.uid));
  108. });
  109. }