Browse Source

fix(AudioOnly+web): crash when untoggle audio only

Because on web video track is stored both in redux and in 'localVideo'
field, video is attempted to be unmuted twice when turning off the audio
only mode. This will crash the app with 'unmute operation is already in
progress'. This commit will prevent from taking action from the web
world if the video track already exists and will make the redux side
rollback unmuted status in case unmute fails.
j8
paweldomas 8 years ago
parent
commit
122a7f6346

+ 20
- 1
conference.js View File

@@ -752,6 +752,9 @@ export default {
752 752
         if (!this._localTracksInitialized) {
753 753
             this.videoMuted = mute;
754 754
 
755
+            return;
756
+        } else if (localVideo && localVideo.isMuted() === mute) {
757
+            // NO-OP
755 758
             return;
756 759
         }
757 760
 
@@ -1994,7 +1997,23 @@ export default {
1994 1997
         );
1995 1998
 
1996 1999
         APP.UI.addListener(UIEvents.TOGGLE_AUDIO_ONLY, audioOnly => {
1997
-            this.muteVideo(audioOnly);
2000
+
2001
+            // FIXME On web video track is stored both in redux and in
2002
+            // 'localVideo' field, video is attempted to be unmuted twice when
2003
+            // turning off the audio only mode. This will crash the app with
2004
+            // 'unmute operation is already in progress'.
2005
+            // Because there's no logic in redux about creating new track in
2006
+            // case unmute when not track exists the things have to go through
2007
+            // muteVideo logic in such case.
2008
+            const tracks = APP.store.getState()['features/base/tracks'];
2009
+            const isTrackInRedux
2010
+                = Boolean(
2011
+                    tracks.find(
2012
+                        track => track.jitsiTrack
2013
+                            && track.jitsiTrack.getType() === 'video'));
2014
+            if (!isTrackInRedux) {
2015
+                this.muteVideo(audioOnly);
2016
+            }
1998 2017
 
1999 2018
             // Immediately update the UI by having remote videos and the large
2000 2019
             // video update themselves instead of waiting for some other event

+ 11
- 2
react/features/base/media/middleware.js View File

@@ -9,7 +9,7 @@ import {
9 9
     setCameraFacingMode,
10 10
     setVideoMuted
11 11
 } from './actions';
12
-import { CAMERA_FACING_MODE } from './constants';
12
+import { CAMERA_FACING_MODE, MEDIA_TYPE } from './constants';
13 13
 
14 14
 /**
15 15
  * Middleware that captures CONFERENCE_LEFT action and restores initial state
@@ -70,6 +70,15 @@ function _syncTrackMutedState(store, track) {
70 70
     // fired before track gets to state.
71 71
     if (track.muted !== muted) {
72 72
         track.muted = muted;
73
-        setTrackMuted(track.jitsiTrack, muted);
73
+        setTrackMuted(track.jitsiTrack, muted)
74
+            .catch(error => {
75
+                console.error(`setTrackMuted(${muted}) failed`, error);
76
+                const setMuted
77
+                    = track.mediaType === MEDIA_TYPE.AUDIO
78
+                        ? setAudioMuted : setVideoMuted;
79
+
80
+                // Failed to sync muted state - dispatch rollback action
81
+                store.dispatch(setMuted(!muted));
82
+            });
74 83
     }
75 84
 }

+ 1
- 5
react/features/base/tracks/functions.js View File

@@ -174,9 +174,5 @@ export function setTrackMuted(track, muted) {
174 174
 
175 175
     const f = muted ? 'mute' : 'unmute';
176 176
 
177
-    return track[f]()
178
-        .catch(err => {
179
-            console.warn(`Track ${f} was rejected:`, err);
180
-            throw err;
181
-        });
177
+    return track[f]();
182 178
 }

+ 13
- 1
react/features/base/tracks/middleware.js View File

@@ -160,7 +160,19 @@ function _getLocalTrack(store, mediaType: MEDIA_TYPE) {
160 160
 function _setMuted(store, action, mediaType: MEDIA_TYPE) {
161 161
     const localTrack = _getLocalTrack(store, mediaType);
162 162
 
163
-    localTrack && setTrackMuted(localTrack.jitsiTrack, action.muted);
163
+    if (localTrack) {
164
+        setTrackMuted(localTrack.jitsiTrack, action.muted)
165
+            .catch(error => {
166
+                console.error(`setTrackMuted(${action.muted}) failed`, error);
167
+
168
+                const setMuted
169
+                    = mediaType === MEDIA_TYPE.AUDIO
170
+                        ? setAudioMuted : setVideoMuted;
171
+
172
+                // Failed to modify muted state - dispatch rollback action
173
+                store.dispatch(setMuted(!action.muted));
174
+            });
175
+    }
164 176
 }
165 177
 
166 178
 /**

Loading…
Cancel
Save