ソースを参照

rn: fix losing audio if call is hangup too quickly

This PR changes the logic for connecting / disconnecting conferences. Instead of
doing it in mount / unmount events from the Conference component, it moves the
logic to the appNavigatee action.

This fixes a regression introduced in 774c5ecd when trying to make sure the
conference terminated event is always sent.

By moving the logic to appNavigate we no longer depend on side-effects for
connecting / disconnecting, and the code should be more maintainable moving
forward.

An improvement to this is the concept of sessions, which, while not tackled
here, was taken into consideration.
master
Saúl Ibarra Corretgé 6年前
コミット
a4cf79c161

+ 21
- 6
react/features/app/actions.js ファイルの表示

@@ -10,8 +10,9 @@ import {
10 10
     setConfig,
11 11
     storeConfig
12 12
 } from '../base/config';
13
-import { setLocationURL } from '../base/connection';
13
+import { connect, disconnect, setLocationURL } from '../base/connection';
14 14
 import { loadConfig } from '../base/lib-jitsi-meet';
15
+import { createDesiredLocalTracks } from '../base/tracks';
15 16
 import { parseURIString, toURLString } from '../base/util';
16 17
 import { setFatalError } from '../overlay';
17 18
 
@@ -58,6 +59,12 @@ export function appNavigate(uri: ?string) {
58 59
         const { contextRoot, host, room } = location;
59 60
         const locationURL = new URL(location.toString());
60 61
 
62
+        // Disconnect from any current conference.
63
+        // FIXME: unify with web.
64
+        if (navigator.product === 'ReactNative') {
65
+            dispatch(disconnect());
66
+        }
67
+
61 68
         dispatch(configWillLoad(locationURL, room));
62 69
 
63 70
         let protocol = location.protocol.toLowerCase();
@@ -87,12 +94,20 @@ export function appNavigate(uri: ?string) {
87 94
             }
88 95
         }
89 96
 
90
-        if (getState()['features/base/config'].locationURL === locationURL) {
91
-            dispatch(setLocationURL(locationURL));
92
-            dispatch(setConfig(config));
93
-            dispatch(setRoom(room));
94
-        } else {
97
+        if (getState()['features/base/config'].locationURL !== locationURL) {
95 98
             dispatch(loadConfigError(new Error('Config no longer needed!'), locationURL));
99
+
100
+            return;
101
+        }
102
+
103
+        dispatch(setLocationURL(locationURL));
104
+        dispatch(setConfig(config));
105
+        dispatch(setRoom(room));
106
+
107
+        // FIXME: unify with web, currently the connection and track creation happens in conference.js.
108
+        if (room && navigator.product === 'ReactNative') {
109
+            dispatch(createDesiredLocalTracks());
110
+            dispatch(connect());
96 111
         }
97 112
     };
98 113
 }

+ 1
- 51
react/features/base/conference/middleware.js ファイルの表示

@@ -24,7 +24,6 @@ import { TRACK_ADDED, TRACK_REMOVED } from '../tracks';
24 24
 
25 25
 import {
26 26
     conferenceFailed,
27
-    conferenceLeft,
28 27
     conferenceWillLeave,
29 28
     createConference,
30 29
     setLastN,
@@ -37,8 +36,7 @@ import {
37 36
     CONFERENCE_WILL_LEAVE,
38 37
     DATA_CHANNEL_OPENED,
39 38
     SET_AUDIO_ONLY,
40
-    SET_LASTN,
41
-    SET_ROOM
39
+    SET_LASTN
42 40
 } from './actionTypes';
43 41
 import {
44 42
     _addLocalTracksToConference,
@@ -99,9 +97,6 @@ MiddlewareRegistry.register(store => next => action => {
99 97
     case SET_LASTN:
100 98
         return _setLastN(store, next, action);
101 99
 
102
-    case SET_ROOM:
103
-        return _setRoom(store, next, action);
104
-
105 100
     case TRACK_ADDED:
106 101
     case TRACK_REMOVED:
107 102
         return _trackAddedOrRemoved(store, next, action);
@@ -566,51 +561,6 @@ function _setReceiverVideoConstraint(conference, preferred, max) {
566 561
     }
567 562
 }
568 563
 
569
-/**
570
- * Notifies the feature {@code base/conference} that the redix action
571
- * {@link SET_ROOM} is being dispatched within a specific redux store.
572
- *
573
- * @param {Store} store - The redux store in which the specified {@code action}
574
- * is being dispatched.
575
- * @param {Dispatch} next - The redux {@code dispatch} function to dispatch the
576
- * specified {@code action} to the specified {@code store}.
577
- * @param {Action} action - The redux action {@code SET_ROOM} which is being
578
- * dispatched in the specified {@code store}.
579
- * @private
580
- * @returns {Object} The value returned by {@code next(action)}.
581
- */
582
-function _setRoom({ dispatch, getState }, next, action) {
583
-    const result = next(action);
584
-
585
-    // By the time SET_ROOM is dispatched, base/connection's locationURL and
586
-    // base/conference's leaving should be the only conference-related sources
587
-    // of truth.
588
-    const state = getState();
589
-    const { leaving } = state['features/base/conference'];
590
-    const { locationURL } = state['features/base/connection'];
591
-    const dispatchConferenceLeft = new Set();
592
-
593
-    // Figure out which of the JitsiConferences referenced by base/conference
594
-    // have not dispatched or are not likely to dispatch CONFERENCE_FAILED and
595
-    // CONFERENCE_LEFT.
596
-    forEachConference(state, (conference, url) => {
597
-        if (conference !== leaving && url && url !== locationURL) {
598
-            dispatchConferenceLeft.add(conference);
599
-        }
600
-
601
-        return true; // All JitsiConference instances are to be examined.
602
-    });
603
-
604
-    // Dispatch CONFERENCE_LEFT for the JitsiConferences referenced by
605
-    // base/conference which have not dispatched or are not likely to dispatch
606
-    // CONFERENCE_FAILED or CONFERENCE_LEFT.
607
-    for (const conference of dispatchConferenceLeft) {
608
-        dispatch(conferenceLeft(conference));
609
-    }
610
-
611
-    return result;
612
-}
613
-
614 564
 /**
615 565
  * Synchronizes local tracks from state with local tracks in JitsiConference
616 566
  * instance.

+ 1
- 4
react/features/base/connection/actions.native.js ファイルの表示

@@ -370,10 +370,7 @@ export function disconnect() {
370 370
         if (connection_) {
371 371
             promise = promise.then(() => connection_.disconnect());
372 372
         } else {
373
-            // FIXME: We have no connection! Fake a disconnect. Because of how the current disconnec is implemented
374
-            // (by doing the diconnect() in the Conference component unmount) we have lost the location URL already.
375
-            // Oh well, at least send the event.
376
-            promise.then(() => dispatch(_connectionDisconnected({}, '')));
373
+            logger.info('No connection found while disconnecting.');
377 374
         }
378 375
 
379 376
         return promise;

+ 4
- 76
react/features/conference/components/native/Conference.js ファイルの表示

@@ -5,7 +5,6 @@ import React from 'react';
5 5
 import { BackHandler, SafeAreaView, StatusBar, View } from 'react-native';
6 6
 
7 7
 import { appNavigate } from '../../../app';
8
-import { connect, disconnect } from '../../../base/connection';
9 8
 import { getParticipantCount } from '../../../base/participants';
10 9
 import { Container, LoadingIndicator, TintedView } from '../../../base/react';
11 10
 import { connect as reactReduxConnect } from '../../../base/redux';
@@ -14,7 +13,6 @@ import {
14 13
     makeAspectRatioAware
15 14
 } from '../../../base/responsive-ui';
16 15
 import { TestConnectionInfo } from '../../../base/testing';
17
-import { createDesiredLocalTracks } from '../../../base/tracks';
18 16
 import { ConferenceNotification } from '../../../calendar-sync';
19 17
 import { Chat } from '../../../chat';
20 18
 import { DisplayNameLabel } from '../../../display-name';
@@ -66,29 +64,6 @@ type Props = AbstractProps & {
66 64
      */
67 65
     _largeVideoParticipantId: string,
68 66
 
69
-    /**
70
-     * Current conference's full URL.
71
-     *
72
-     * @private
73
-     */
74
-    _locationURL: URL,
75
-
76
-    /**
77
-     * The handler which dispatches the (redux) action connect.
78
-     *
79
-     * @private
80
-     * @returns {void}
81
-     */
82
-    _onConnect: Function,
83
-
84
-    /**
85
-     * The handler which dispatches the (redux) action disconnect.
86
-     *
87
-     * @private
88
-     * @returns {void}
89
-     */
90
-    _onDisconnect: Function,
91
-
92 67
     /**
93 68
      * Handles a hardware button press for back navigation. Leaves the
94 69
      * associated {@code Conference}.
@@ -166,8 +141,6 @@ class Conference extends AbstractConference<Props, *> {
166 141
      * @returns {void}
167 142
      */
168 143
     componentDidMount() {
169
-        this.props._onConnect();
170
-
171 144
         BackHandler.addEventListener(
172 145
             'hardwareBackPress',
173 146
             this.props._onHardwareBackPress);
@@ -184,26 +157,16 @@ class Conference extends AbstractConference<Props, *> {
184 157
      *
185 158
      * @inheritdoc
186 159
      */
187
-    componentDidUpdate(pevProps: Props) {
160
+    componentDidUpdate(prevProps: Props) {
188 161
         const {
189
-            _locationURL: oldLocationURL,
190
-            _participantCount: oldParticipantCount,
191
-            _room: oldRoom
192
-        } = pevProps;
162
+            _participantCount: oldParticipantCount
163
+        } = prevProps;
193 164
         const {
194
-            _locationURL: newLocationURL,
195 165
             _participantCount: newParticipantCount,
196
-            _room: newRoom,
197 166
             _setToolboxVisible,
198 167
             _toolboxVisible
199 168
         } = this.props;
200 169
 
201
-        // If the location URL changes we need to reconnect.
202
-        oldLocationURL !== newLocationURL && newRoom && this.props._onDisconnect();
203
-
204
-        // Start the connection process when there is a (valid) room.
205
-        oldRoom !== newRoom && newRoom && this.props._onConnect();
206
-
207 170
         if (oldParticipantCount === 1
208 171
                 && newParticipantCount > 1
209 172
                 && _toolboxVisible) {
@@ -228,8 +191,6 @@ class Conference extends AbstractConference<Props, *> {
228 191
         BackHandler.removeEventListener(
229 192
             'hardwareBackPress',
230 193
             this.props._onHardwareBackPress);
231
-
232
-        this.props._onDisconnect();
233 194
     }
234 195
 
235 196
     /**
@@ -396,36 +357,12 @@ class Conference extends AbstractConference<Props, *> {
396 357
  * @param {Function} dispatch - Redux action dispatcher.
397 358
  * @private
398 359
  * @returns {{
399
- *     _onConnect: Function,
400
- *     _onDisconnect: Function,
401 360
  *     _onHardwareBackPress: Function,
402 361
  *     _setToolboxVisible: Function
403 362
  * }}
404 363
  */
405 364
 function _mapDispatchToProps(dispatch) {
406 365
     return {
407
-        /**
408
-         * Dispatches actions to create the desired local tracks and for
409
-         * connecting to the conference.
410
-         *
411
-         * @private
412
-         * @returns {void}
413
-         */
414
-        _onConnect() {
415
-            dispatch(createDesiredLocalTracks());
416
-            dispatch(connect());
417
-        },
418
-
419
-        /**
420
-         * Dispatches an action disconnecting from the conference.
421
-         *
422
-         * @private
423
-         * @returns {void}
424
-         */
425
-        _onDisconnect() {
426
-            dispatch(disconnect());
427
-        },
428
-
429 366
         /**
430 367
          * Handles a hardware button press for back navigation. Leaves the
431 368
          * associated {@code Conference}.
@@ -462,8 +399,7 @@ function _mapDispatchToProps(dispatch) {
462 399
  * @returns {Props}
463 400
  */
464 401
 function _mapStateToProps(state) {
465
-    const { connecting, connection, locationURL }
466
-        = state['features/base/connection'];
402
+    const { connecting, connection } = state['features/base/connection'];
467 403
     const {
468 404
         conference,
469 405
         joining,
@@ -508,14 +444,6 @@ function _mapStateToProps(state) {
508 444
          */
509 445
         _largeVideoParticipantId: state['features/large-video'].participantId,
510 446
 
511
-        /**
512
-         * Current conference's full URL.
513
-         *
514
-         * @private
515
-         * @type {URL}
516
-         */
517
-        _locationURL: locationURL,
518
-
519 447
         /**
520 448
          * The number of participants in the conference.
521 449
          *

+ 25
- 8
react/features/toolbox/components/HangupButton.js ファイルの表示

@@ -1,5 +1,6 @@
1 1
 // @flow
2 2
 
3
+import _ from 'lodash';
3 4
 
4 5
 import { createToolbarEvent, sendAnalytics } from '../../analytics';
5 6
 import { appNavigate } from '../../app';
@@ -26,10 +27,33 @@ type Props = AbstractButtonProps & {
26 27
  * @extends AbstractHangupButton
27 28
  */
28 29
 class HangupButton extends AbstractHangupButton<Props, *> {
30
+    _hangup: Function;
31
+
29 32
     accessibilityLabel = 'toolbar.accessibilityLabel.hangup';
30 33
     label = 'toolbar.hangup';
31 34
     tooltip = 'toolbar.hangup';
32 35
 
36
+    /**
37
+     * Initializes a new HangupButton instance.
38
+     *
39
+     * @param {Props} props - The read-only properties with which the new
40
+     * instance is to be initialized.
41
+     */
42
+    constructor(props: Props) {
43
+        super(props);
44
+
45
+        this._hangup = _.once(() => {
46
+            sendAnalytics(createToolbarEvent('hangup'));
47
+
48
+            // FIXME: these should be unified.
49
+            if (navigator.product === 'ReactNative') {
50
+                this.props.dispatch(appNavigate(undefined));
51
+            } else {
52
+                this.props.dispatch(disconnect(true));
53
+            }
54
+        });
55
+    }
56
+
33 57
     /**
34 58
      * Helper function to perform the actual hangup action.
35 59
      *
@@ -38,14 +62,7 @@ class HangupButton extends AbstractHangupButton<Props, *> {
38 62
      * @returns {void}
39 63
      */
40 64
     _doHangup() {
41
-        sendAnalytics(createToolbarEvent('hangup'));
42
-
43
-        // FIXME: these should be unified.
44
-        if (navigator.product === 'ReactNative') {
45
-            this.props.dispatch(appNavigate(undefined));
46
-        } else {
47
-            this.props.dispatch(disconnect(true));
48
-        }
65
+        this._hangup();
49 66
     }
50 67
 }
51 68
 

読み込み中…
キャンセル
保存