Преглед на файлове

ref: enable/disable microphone button

Make toolbar's microphone button enabled whenever there are any
'audioinput' devices available and allow to add audio during
the conference even if microphone permissions were denied on startup.
efficient_tiling
paweldomas преди 7 години
родител
ревизия
68f4a4ae9f

+ 45
- 18
conference.js Целия файл

@@ -33,7 +33,10 @@ import { updateDeviceList } from './react/features/base/devices';
33 33
 import {
34 34
     isFatalJitsiConnectionError
35 35
 } from './react/features/base/lib-jitsi-meet';
36
-import { setVideoAvailable } from './react/features/base/media';
36
+import {
37
+    setAudioAvailable,
38
+    setVideoAvailable
39
+} from './react/features/base/media';
37 40
 import {
38 41
     localParticipantConnectionStatusChanged,
39 42
     localParticipantRoleChanged,
@@ -671,24 +674,17 @@ export default {
671 674
                 }
672 675
 
673 676
                 // if user didn't give access to mic or camera or doesn't have
674
-                // them at all, we disable corresponding toolbar buttons
677
+                // them at all, we mark corresponding toolbar buttons as muted,
678
+                // so that the user can try unmute later on and add audio/video
679
+                // to the conference
675 680
                 if (!tracks.find((t) => t.isAudioTrack())) {
676
-                    APP.UI.setMicrophoneButtonEnabled(false);
681
+                    this.audioMuted = true;
682
+                    APP.UI.setAudioMuted(this.getMyUserId(), this.audioMuted);
677 683
                 }
678 684
 
679 685
                 if (!tracks.find((t) => t.isVideoTrack())) {
680
-                    // Instead of disabling the button we want to show button
681
-                    // muted, so that the user can have the opportunity to add
682
-                    // the video later on, even if joined without it.
683 686
                     this.videoMuted = true;
684 687
                     APP.UI.setVideoMuted(this.getMyUserId(), this.videoMuted);
685
-                    // FIXME this is a workaround for the situation where
686
-                    // both audio and video permissions are rejected initially
687
-                    // and the callback from _initDeviceList will never be
688
-                    // executed (GUM not initialized - check lib-jitsi-meet).
689
-                    // The goal here is to disable the video icon in case no
690
-                    // video permissions were granted.
691
-                    this.updateVideoIconEnabled();
692 688
                 }
693 689
 
694 690
                 this._initDeviceList();
@@ -1156,7 +1152,6 @@ export default {
1156 1152
                     this.isSharingScreen = false;
1157 1153
                 }
1158 1154
                 APP.UI.setVideoMuted(this.getMyUserId(), this.videoMuted);
1159
-                this.updateVideoIconEnabled();
1160 1155
                 APP.UI.updateDesktopSharingButtons();
1161 1156
             });
1162 1157
     },
@@ -1178,7 +1173,6 @@ export default {
1178 1173
                 } else {
1179 1174
                     this.audioMuted = false;
1180 1175
                 }
1181
-                APP.UI.setMicrophoneButtonEnabled(true);
1182 1176
                 APP.UI.setAudioMuted(this.getMyUserId(), this.audioMuted);
1183 1177
             });
1184 1178
     },
@@ -1799,7 +1793,19 @@ export default {
1799 1793
             APP.UI.updateDTMFSupport(isDTMFSupported);
1800 1794
         });
1801 1795
 
1802
-        APP.UI.addListener(UIEvents.AUDIO_MUTED, muteLocalAudio);
1796
+        APP.UI.addListener(UIEvents.AUDIO_MUTED, muted => {
1797
+            if (!localAudio && this.audioMuted && !muted) {
1798
+                createLocalTracks({ devices: ['audio'] }, false)
1799
+                    .then(([audioTrack]) => {
1800
+                        this.useAudioStream(audioTrack);
1801
+                    })
1802
+                    .catch(error => {
1803
+                        APP.UI.showDeviceErrorDialog(error, null);
1804
+                    });
1805
+            } else {
1806
+                muteLocalAudio(muted);
1807
+            }
1808
+        });
1803 1809
         APP.UI.addListener(UIEvents.VIDEO_MUTED, muted => {
1804 1810
             if (this.isAudioOnly() && !muted) {
1805 1811
                 this._displayAudioOnlyTooltip('videoMute');
@@ -2139,7 +2145,6 @@ export default {
2139 2145
                         mediaDeviceHelper.setCurrentMediaDevices(devices);
2140 2146
                         APP.UI.onAvailableDevicesChanged(devices);
2141 2147
                         APP.store.dispatch(updateDeviceList(devices));
2142
-                        this.updateVideoIconEnabled();
2143 2148
                     });
2144 2149
 
2145 2150
                     this.deviceChangeListener = (devices) =>
@@ -2221,9 +2226,31 @@ export default {
2221 2226
             .then(() => {
2222 2227
                 mediaDeviceHelper.setCurrentMediaDevices(devices);
2223 2228
                 APP.UI.onAvailableDevicesChanged(devices);
2224
-                this.updateVideoIconEnabled();
2225 2229
             });
2226 2230
     },
2231
+
2232
+    /**
2233
+     * Determines whether or not the audio button should be enabled.
2234
+     */
2235
+    updateAudioIconEnabled() {
2236
+        const audioMediaDevices
2237
+            = mediaDeviceHelper.getCurrentMediaDevices().audioinput;
2238
+        const audioDeviceCount
2239
+            = audioMediaDevices ? audioMediaDevices.length : 0;
2240
+
2241
+        // The audio functionality is considered available if there are any
2242
+        // audio devices detected or if the local audio stream already exists.
2243
+        const available = audioDeviceCount > 0 || Boolean(localAudio);
2244
+
2245
+        logger.debug(
2246
+            'Microphone button enabled: ' + available,
2247
+            'local audio: ' + localAudio,
2248
+            'audio devices: ' + audioMediaDevices,
2249
+            'device count: ' + audioDeviceCount);
2250
+
2251
+        APP.store.dispatch(setAudioAvailable(available));
2252
+    },
2253
+
2227 2254
     /**
2228 2255
      * Determines whether or not the video button should be enabled.
2229 2256
      */

+ 4
- 13
modules/UI/UI.js Целия файл

@@ -32,7 +32,6 @@ import {
32 32
 import {
33 33
     checkAutoEnableDesktopSharing,
34 34
     dockToolbox,
35
-    setAudioIconEnabled,
36 35
     setToolbarButton,
37 36
     showDialPadButton,
38 37
     showEtherpadButton,
@@ -710,9 +709,7 @@ UI.setAudioMuted = function (id, muted) {
710 709
     VideoLayout.onAudioMute(id, muted);
711 710
     if (APP.conference.isLocalId(id)) {
712 711
         APP.store.dispatch(setAudioMuted(muted));
713
-        APP.store.dispatch(setToolbarButton('microphone', {
714
-            toggled: muted
715
-        }));
712
+        APP.conference.updateAudioIconEnabled();
716 713
     }
717 714
 };
718 715
 
@@ -723,6 +720,7 @@ UI.setVideoMuted = function (id, muted) {
723 720
     VideoLayout.onVideoMute(id, muted);
724 721
     if (APP.conference.isLocalId(id)) {
725 722
         APP.store.dispatch(setVideoMuted(muted));
723
+        APP.conference.updateVideoIconEnabled();
726 724
     }
727 725
 };
728 726
 
@@ -1096,6 +1094,8 @@ UI.onLocalRaiseHandChanged = function (isRaisedHand) {
1096 1094
  */
1097 1095
 UI.onAvailableDevicesChanged = function (devices) {
1098 1096
     APP.store.dispatch(updateDeviceList(devices));
1097
+    APP.conference.updateAudioIconEnabled();
1098
+    APP.conference.updateVideoIconEnabled();
1099 1099
 };
1100 1100
 
1101 1101
 /**
@@ -1367,15 +1367,6 @@ UI.onSharedVideoStop = function (id, attributes) {
1367 1367
         sharedVideoManager.onSharedVideoStop(id, attributes);
1368 1368
 };
1369 1369
 
1370
-/**
1371
- * Enables / disables microphone toolbar button.
1372
- *
1373
- * @param {boolean} enabled indicates if the microphone button should be
1374
- * enabled or disabled
1375
- */
1376
-UI.setMicrophoneButtonEnabled
1377
-    = enabled => APP.store.dispatch(setAudioIconEnabled(enabled));
1378
-
1379 1370
 /**
1380 1371
  * Indicates if any the "top" overlays are currently visible. The check includes
1381 1372
  * the call/ring overlay, the suspended overlay, the GUM permissions overlay,

+ 0
- 5
modules/devices/mediaDeviceHelper.js Целия файл

@@ -55,11 +55,6 @@ function getNewAudioInputDevice(newDevices, localAudio) {
55 55
             availableAudioInputDevices[0].label !== '') {
56 56
             return availableAudioInputDevices[0].deviceId;
57 57
         }
58
-        // Otherwise we assume that we don't have any audio input devices
59
-        // to use and that's why disable microphone button on UI.
60
-        else {
61
-            APP.UI.setMicrophoneButtonEnabled(false);
62
-        }
63 58
     } else {
64 59
         // And here we handle case when we already have some device working,
65 60
         // but we plug-in a "preferred" (previously selected in settings, stored

+ 10
- 0
react/features/base/media/actionTypes.js Целия файл

@@ -8,6 +8,16 @@
8 8
  */
9 9
 export const SET_AUDIO_MUTED = Symbol('SET_AUDIO_MUTED');
10 10
 
11
+/**
12
+ * The type of (redux) action to adjust the availability of the local audio.
13
+ *
14
+ * {
15
+ *     type: SET_AUDIO_AVAILABLE,
16
+ *     muted: boolean
17
+ * }
18
+ */
19
+export const SET_AUDIO_AVAILABLE = Symbol('SET_AUDIO_AVAILABLE');
20
+
11 21
 /**
12 22
  * The type of (redux) action to set the facing mode of the local video camera
13 23
  * to a specific value.

+ 18
- 0
react/features/base/media/actions.js Целия файл

@@ -4,6 +4,7 @@ import type { Dispatch } from 'redux';
4 4
 
5 5
 import {
6 6
     SET_AUDIO_MUTED,
7
+    SET_AUDIO_AVAILABLE,
7 8
     SET_CAMERA_FACING_MODE,
8 9
     SET_VIDEO_AVAILABLE,
9 10
     SET_VIDEO_MUTED,
@@ -11,6 +12,23 @@ import {
11 12
 } from './actionTypes';
12 13
 import { CAMERA_FACING_MODE } from './constants';
13 14
 
15
+/**
16
+ * Action to adjust the availability of the local audio.
17
+ *
18
+ * @param {boolean} available - True if the local audio is to be marked as
19
+ * available or false if the local audio is not available.
20
+ * @returns {{
21
+ *      type: SET_AUDIO_AVAILABLE,
22
+ *      available: boolean
23
+ *  }}
24
+ */
25
+export function setAudioAvailable(available: boolean) {
26
+    return {
27
+        type: SET_AUDIO_AVAILABLE,
28
+        available
29
+    };
30
+}
31
+
14 32
 /**
15 33
  * Action to set the muted state of the local audio.
16 34
  *

+ 8
- 0
react/features/base/media/reducer.js Целия файл

@@ -3,6 +3,7 @@ import { combineReducers } from 'redux';
3 3
 import { ReducerRegistry } from '../redux';
4 4
 
5 5
 import {
6
+    SET_AUDIO_AVAILABLE,
6 7
     SET_AUDIO_MUTED,
7 8
     SET_CAMERA_FACING_MODE,
8 9
     SET_VIDEO_AVAILABLE,
@@ -24,6 +25,7 @@ import { CAMERA_FACING_MODE } from './constants';
24 25
  * @type {AudioMediaState}
25 26
  */
26 27
 const AUDIO_INITIAL_MEDIA_STATE = {
28
+    available: true,
27 29
     muted: false
28 30
 };
29 31
 
@@ -38,6 +40,12 @@ const AUDIO_INITIAL_MEDIA_STATE = {
38 40
  */
39 41
 function _audio(state = AUDIO_INITIAL_MEDIA_STATE, action) {
40 42
     switch (action.type) {
43
+    case SET_AUDIO_AVAILABLE:
44
+        return {
45
+            ...state,
46
+            available: action.available
47
+        };
48
+
41 49
     case SET_AUDIO_MUTED:
42 50
         return {
43 51
             ...state,

+ 0
- 21
react/features/toolbox/actions.native.js Целия файл

@@ -51,27 +51,6 @@ export function clearToolboxTimeout(): Object {
51 51
     };
52 52
 }
53 53
 
54
-/**
55
- * Enables/disables audio toolbar button.
56
- *
57
- * @param {boolean} enabled - True if the button should be enabled; otherwise,
58
- * false.
59
- * @returns {Function}
60
- */
61
-export function setAudioIconEnabled(enabled: boolean = false): Function {
62
-    return (dispatch: Dispatch<*>) => {
63
-        const i18nKey = enabled ? 'mute' : 'micDisabled';
64
-        const i18n = `[content]toolbar.${i18nKey}`;
65
-        const button = {
66
-            enabled,
67
-            i18n,
68
-            toggled: !enabled
69
-        };
70
-
71
-        dispatch(setToolbarButton('microphone', button));
72
-    };
73
-}
74
-
75 54
 /**
76 55
  * Signals that value of conference subject should be changed.
77 56
  *

+ 35
- 1
react/features/toolbox/middleware.js Целия файл

@@ -1,6 +1,10 @@
1 1
 /* @flow */
2 2
 
3
-import { SET_VIDEO_AVAILABLE, SET_VIDEO_MUTED } from '../base/media';
3
+import {
4
+    SET_AUDIO_AVAILABLE,
5
+    SET_AUDIO_MUTED,
6
+    SET_VIDEO_AVAILABLE,
7
+    SET_VIDEO_MUTED } from '../base/media';
4 8
 import { MiddlewareRegistry } from '../base/redux';
5 9
 
6 10
 import { setToolbarButton } from './actions';
@@ -33,6 +37,11 @@ MiddlewareRegistry.register(store => next => action => {
33 37
         break;
34 38
     }
35 39
 
40
+    case SET_AUDIO_AVAILABLE:
41
+    case SET_AUDIO_MUTED: {
42
+        return _setAudioAvailableOrMuted(store, next, action);
43
+    }
44
+
36 45
     case SET_VIDEO_AVAILABLE:
37 46
     case SET_VIDEO_MUTED:
38 47
         return _setVideoAvailableOrMuted(store, next, action);
@@ -41,6 +50,31 @@ MiddlewareRegistry.register(store => next => action => {
41 50
     return next(action);
42 51
 });
43 52
 
53
+/**
54
+ * Adjusts the state of toolbar's microphone button.
55
+ *
56
+ * @param {Store} store - The Redux store instance.
57
+ * @param {Function} next - The redux function to continue dispatching the
58
+ * specified {@code action} in the specified {@code store}.
59
+ * @param {Object} action - Either SET_AUDIO_AVAILABLE or SET_AUDIO_MUTED.
60
+ *
61
+ * @returns {*}
62
+ */
63
+function _setAudioAvailableOrMuted({ dispatch, getState }, next, action) {
64
+    const result = next(action);
65
+
66
+    const { available, muted } = getState()['features/base/media'].audio;
67
+    const i18nKey = available ? 'mute' : 'micDisabled';
68
+
69
+    dispatch(setToolbarButton('microphone', {
70
+        enabled: available,
71
+        i18n: `[content]toolbar.${i18nKey}`,
72
+        toggled: available ? muted : true
73
+    }));
74
+
75
+    return result;
76
+}
77
+
44 78
 /**
45 79
  * Adjusts the state of toolbar's camera button.
46 80
  *

Loading…
Отказ
Запис