Browse Source

fix(tracks): Do not signal muted audio tracks.

Do not add the muted audio tracks to peerconnection until the user unmutes the first time. This applies to startSilent, startWithAudioMuted and startAudioMuted/startVideoMuted config.js settings.
j8
Jaya Allamsetty 4 years ago
parent
commit
dcda89012e
No account linked to committer's email address
3 changed files with 62 additions and 32 deletions
  1. 36
    14
      conference.js
  2. 18
    10
      react/features/base/conference/actions.js
  3. 8
    8
      react/features/prejoin/middleware.js

+ 36
- 14
conference.js View File

99
     destroyLocalTracks,
99
     destroyLocalTracks,
100
     getLocalJitsiAudioTrack,
100
     getLocalJitsiAudioTrack,
101
     getLocalJitsiVideoTrack,
101
     getLocalJitsiVideoTrack,
102
+    getLocalTracks,
102
     isLocalCameraTrackMuted,
103
     isLocalCameraTrackMuted,
103
     isLocalTrackMuted,
104
     isLocalTrackMuted,
104
     isUserInteractionRequiredForUnmute,
105
     isUserInteractionRequiredForUnmute,
473
      */
474
      */
474
     createInitialLocalTracks(options = {}) {
475
     createInitialLocalTracks(options = {}) {
475
         const errors = {};
476
         const errors = {};
477
+
478
+        // Always get a handle on the audio input device so that we have statistics (such as "No audio input" or
479
+        // "Are you trying to speak?" ) even if the user joins the conference muted.
476
         const initialDevices = config.disableInitialGUM ? [] : [ 'audio' ];
480
         const initialDevices = config.disableInitialGUM ? [] : [ 'audio' ];
477
         const requestedAudio = !config.disableInitialGUM;
481
         const requestedAudio = !config.disableInitialGUM;
478
         let requestedVideo = false;
482
         let requestedVideo = false;
479
 
483
 
480
-        // Always get a handle on the audio input device so that we have statistics even if the user joins the
481
-        // conference muted. Previous implementation would only acquire the handle when the user first unmuted,
482
-        // which would results in statistics ( such as "No audio input" or "Are you trying to speak?") being available
483
-        // only after that point.
484
-        if (options.startWithAudioMuted) {
485
-            this.muteAudio(true, true);
486
-        }
487
-
488
         if (!config.disableInitialGUM
484
         if (!config.disableInitialGUM
489
                 && !options.startWithVideoMuted
485
                 && !options.startWithVideoMuted
490
                 && !options.startAudioOnly
486
                 && !options.startAudioOnly
824
             return this._setLocalAudioVideoStreams(tracks);
820
             return this._setLocalAudioVideoStreams(tracks);
825
         }
821
         }
826
 
822
 
827
-        const [ tracks, con ] = await this.createInitialLocalTracksAndConnect(
828
-            roomName, initialOptions);
823
+        const [ tracks, con ] = await this.createInitialLocalTracksAndConnect(roomName, initialOptions);
824
+        let localTracks = tracks;
829
 
825
 
830
         this._initDeviceList(true);
826
         this._initDeviceList(true);
831
 
827
 
832
-        return this.startConference(con, tracks);
828
+        if (initialOptions.startWithAudioMuted) {
829
+            localTracks = localTracks.filter(track => track.getType() !== MEDIA_TYPE.AUDIO);
830
+        }
831
+
832
+        return this.startConference(con, localTracks);
833
     },
833
     },
834
 
834
 
835
     /**
835
     /**
1320
                 this._getConferenceOptions());
1320
                 this._getConferenceOptions());
1321
 
1321
 
1322
         APP.store.dispatch(conferenceWillJoin(room));
1322
         APP.store.dispatch(conferenceWillJoin(room));
1323
-        this._setLocalAudioVideoStreams(localTracks);
1323
+
1324
+        // Filter out the tracks that are muted.
1325
+        const tracks = localTracks.filter(track => !track.isMuted());
1326
+
1327
+        this._setLocalAudioVideoStreams(tracks);
1324
         this._room = room; // FIXME do not use this
1328
         this._room = room; // FIXME do not use this
1325
 
1329
 
1326
         sendLocalParticipant(APP.store, room);
1330
         sendLocalParticipant(APP.store, room);
2163
             }
2167
             }
2164
         );
2168
         );
2165
         room.on(JitsiConferenceEvents.STARTED_MUTED, () => {
2169
         room.on(JitsiConferenceEvents.STARTED_MUTED, () => {
2166
-            (room.isStartAudioMuted() || room.isStartVideoMuted())
2167
-                && APP.UI.notifyInitiallyMuted();
2170
+            const audioMuted = room.isStartAudioMuted();
2171
+            const videoMuted = room.isStartVideoMuted();
2172
+            const localTracks = getLocalTracks(APP.store.getState()['features/base/tracks']);
2173
+            const promises = [];
2174
+
2175
+            APP.store.dispatch(setAudioMuted(audioMuted));
2176
+            APP.store.dispatch(setVideoMuted(videoMuted));
2177
+
2178
+            // Remove the tracks from the peerconnection.
2179
+            for (const track of localTracks) {
2180
+                if (audioMuted && track.jitsiTrack?.getType() === MEDIA_TYPE.AUDIO) {
2181
+                    promises.push(this.useAudioStream(null));
2182
+                }
2183
+                if (videoMuted && track.jitsiTrack?.getType() === MEDIA_TYPE.VIDEO) {
2184
+                    promises.push(this.useVideoStream(null));
2185
+                }
2186
+            }
2187
+
2188
+            Promise.allSettled(promises)
2189
+                .then(() => APP.UI.notifyInitiallyMuted());
2168
         });
2190
         });
2169
 
2191
 
2170
         room.on(
2192
         room.on(

+ 18
- 10
react/features/base/conference/actions.js View File

10
 import { endpointMessageReceived } from '../../subtitles';
10
 import { endpointMessageReceived } from '../../subtitles';
11
 import { JITSI_CONNECTION_CONFERENCE_KEY } from '../connection';
11
 import { JITSI_CONNECTION_CONFERENCE_KEY } from '../connection';
12
 import { JitsiConferenceEvents } from '../lib-jitsi-meet';
12
 import { JitsiConferenceEvents } from '../lib-jitsi-meet';
13
-import { setAudioMuted, setVideoMuted } from '../media';
13
+import { MEDIA_TYPE, setAudioMuted, setVideoMuted } from '../media';
14
 import {
14
 import {
15
     dominantSpeakerChanged,
15
     dominantSpeakerChanged,
16
     getLocalParticipant,
16
     getLocalParticipant,
22
     participantRoleChanged,
22
     participantRoleChanged,
23
     participantUpdated
23
     participantUpdated
24
 } from '../participants';
24
 } from '../participants';
25
-import { getLocalTracks, trackAdded, trackRemoved } from '../tracks';
25
+import { getLocalTracks, replaceLocalTrack, trackAdded, trackRemoved } from '../tracks';
26
 import {
26
 import {
27
     getBackendSafePath,
27
     getBackendSafePath,
28
     getBackendSafeRoomName,
28
     getBackendSafeRoomName,
72
  *
72
  *
73
  * @param {JitsiConference} conference - The JitsiConference instance.
73
  * @param {JitsiConference} conference - The JitsiConference instance.
74
  * @param {Dispatch} dispatch - The Redux dispatch function.
74
  * @param {Dispatch} dispatch - The Redux dispatch function.
75
+ * @param {Object} state - The Redux state.
75
  * @private
76
  * @private
76
  * @returns {void}
77
  * @returns {void}
77
  */
78
  */
78
-function _addConferenceListeners(conference, dispatch) {
79
+function _addConferenceListeners(conference, dispatch, state) {
79
     // A simple logger for conference errors received through
80
     // A simple logger for conference errors received through
80
     // the listener. These errors are not handled now, but logged.
81
     // the listener. These errors are not handled now, but logged.
81
     conference.on(JitsiConferenceEvents.CONFERENCE_ERROR,
82
     conference.on(JitsiConferenceEvents.CONFERENCE_ERROR,
118
     conference.on(
119
     conference.on(
119
         JitsiConferenceEvents.STARTED_MUTED,
120
         JitsiConferenceEvents.STARTED_MUTED,
120
         () => {
121
         () => {
121
-            const audioMuted = Boolean(conference.startAudioMuted);
122
-            const videoMuted = Boolean(conference.startVideoMuted);
122
+            const audioMuted = Boolean(conference.isStartAudioMuted());
123
+            const videoMuted = Boolean(conference.isStartVideoMuted());
124
+            const localTracks = getLocalTracks(state['features/base/tracks']);
123
 
125
 
124
-            sendAnalytics(createStartMutedConfigurationEvent(
125
-                'remote', audioMuted, videoMuted));
126
-            logger.log(`Start muted: ${audioMuted ? 'audio, ' : ''}${
127
-                videoMuted ? 'video' : ''}`);
126
+            sendAnalytics(createStartMutedConfigurationEvent('remote', audioMuted, videoMuted));
127
+            logger.log(`Start muted: ${audioMuted ? 'audio, ' : ''}${videoMuted ? 'video' : ''}`);
128
 
128
 
129
             // XXX Jicofo tells lib-jitsi-meet to start with audio and/or video
129
             // XXX Jicofo tells lib-jitsi-meet to start with audio and/or video
130
             // muted i.e. Jicofo expresses an intent. Lib-jitsi-meet has turned
130
             // muted i.e. Jicofo expresses an intent. Lib-jitsi-meet has turned
136
             // acting on Jicofo's intent without the app's knowledge.
136
             // acting on Jicofo's intent without the app's knowledge.
137
             dispatch(setAudioMuted(audioMuted));
137
             dispatch(setAudioMuted(audioMuted));
138
             dispatch(setVideoMuted(videoMuted));
138
             dispatch(setVideoMuted(videoMuted));
139
+
140
+            // Remove the tracks from peerconnection as well.
141
+            for (const track of localTracks) {
142
+                if ((audioMuted && track.jitsiTrack.getType() === MEDIA_TYPE.AUDIO)
143
+                    || (videoMuted && track.jitsiTrack.getType() === MEDIA_TYPE.VIDEO)) {
144
+                    replaceLocalTrack(track.jitsiTrack, null, conference);
145
+                }
146
+            }
139
         });
147
         });
140
 
148
 
141
     // Dispatches into features/base/tracks follow:
149
     // Dispatches into features/base/tracks follow:
448
 
456
 
449
         dispatch(_conferenceWillJoin(conference));
457
         dispatch(_conferenceWillJoin(conference));
450
 
458
 
451
-        _addConferenceListeners(conference, dispatch);
459
+        _addConferenceListeners(conference, dispatch, state);
452
 
460
 
453
         sendLocalParticipant(state, conference);
461
         sendLocalParticipant(state, conference);
454
 
462
 

+ 8
- 8
react/features/prejoin/middleware.js View File

5
 import { MiddlewareRegistry } from '../base/redux';
5
 import { MiddlewareRegistry } from '../base/redux';
6
 import { updateSettings } from '../base/settings';
6
 import { updateSettings } from '../base/settings';
7
 import {
7
 import {
8
-    getLocalVideoTrack,
8
+    getLocalTracks,
9
     replaceLocalTrack,
9
     replaceLocalTrack,
10
     TRACK_ADDED,
10
     TRACK_ADDED,
11
     TRACK_NO_DATA_FROM_SOURCE
11
     TRACK_NO_DATA_FROM_SOURCE
33
         const { getState, dispatch } = store;
33
         const { getState, dispatch } = store;
34
         const state = getState();
34
         const state = getState();
35
         const { userSelectedSkipPrejoin } = state['features/prejoin'];
35
         const { userSelectedSkipPrejoin } = state['features/prejoin'];
36
-        const localVideoTrack = getLocalVideoTrack(state['features/base/tracks']);
36
+        const localTracks = getLocalTracks(state['features/base/tracks']);
37
         const { options } = action;
37
         const { options } = action;
38
 
38
 
39
         options && store.dispatch(updateConfig(options));
39
         options && store.dispatch(updateConfig(options));
42
             userSelectedSkipPrejoin
42
             userSelectedSkipPrejoin
43
         }));
43
         }));
44
 
44
 
45
-        if (localVideoTrack?.muted) {
46
-            await dispatch(replaceLocalTrack(localVideoTrack.jitsiTrack, null));
45
+        // Do not signal audio/video tracks if the user joins muted.
46
+        for (const track of localTracks) {
47
+            if (track.muted) {
48
+                await dispatch(replaceLocalTrack(track.jitsiTrack, null));
49
+            }
47
         }
50
         }
48
-
49
-        const jitsiTracks = getState()['features/base/tracks']
50
-            .map(t => t.jitsiTrack)
51
-            .filter(t => Boolean(t)); // Filter out GUM in progress tracks...
51
+        const jitsiTracks = localTracks.map(t => t.jitsiTrack);
52
 
52
 
53
         dispatch(setPrejoinPageVisibility(false));
53
         dispatch(setPrejoinPageVisibility(false));
54
         APP.conference.prejoinStart(jitsiTracks);
54
         APP.conference.prejoinStart(jitsiTracks);

Loading…
Cancel
Save