diff --git a/package-lock.json b/package-lock.json index 162824f97..478fdd509 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9641,8 +9641,8 @@ } }, "lib-jitsi-meet": { - "version": "github:jitsi/lib-jitsi-meet#e59d8b4efd52e36750379e9cbd08fd50ab40c1ea", - "from": "github:jitsi/lib-jitsi-meet#e59d8b4efd52e36750379e9cbd08fd50ab40c1ea", + "version": "github:jitsi/lib-jitsi-meet#1bd6ee4b1207e6fd57f5b7c15cc17e0a6087f26d", + "from": "github:jitsi/lib-jitsi-meet#1bd6ee4b1207e6fd57f5b7c15cc17e0a6087f26d", "requires": { "@jitsi/sdp-interop": "0.1.13", "@jitsi/sdp-simulcast": "0.2.1", @@ -13230,9 +13230,9 @@ "integrity": "sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw==" }, "rtcpeerconnection-shim": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.11.tgz", - "integrity": "sha512-Vns4aLKXTrLZCjDOlPZL1nymFiSpqs15TeF+wG1TSLO1kXRrCuT5SjL+Zb8RCP7t3JNfnCuTn+qMlCGQu5NvhQ==", + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.12.tgz", + "integrity": "sha512-7v/mpRyCRjVrTr3pqI9ouXzKGtbSg+iJ54fERZCGYc6AwvkTe6WWeKWG4OmG0H3dWkr1NNASyGieE0Q0hMJviQ==", "requires": { "sdp": "^2.6.0" } diff --git a/package.json b/package.json index 0633c4592..c9c94395a 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "jquery-i18next": "1.2.0", "js-md5": "0.6.1", "jwt-decode": "2.2.0", - "lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#e59d8b4efd52e36750379e9cbd08fd50ab40c1ea", + "lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#1bd6ee4b1207e6fd57f5b7c15cc17e0a6087f26d", "lodash": "4.17.4", "moment": "2.19.4", "postis": "2.2.0", diff --git a/react/features/base/conference/actions.js b/react/features/base/conference/actions.js index 1368c243d..030013b43 100644 --- a/react/features/base/conference/actions.js +++ b/react/features/base/conference/actions.js @@ -199,7 +199,8 @@ export function conferenceFailed(conference: Object, error: string) { // Make the error resemble an Error instance (to the extent that // jitsi-meet needs it). error: { - name: error + name: error, + recoverable: undefined } }; } diff --git a/react/features/base/conference/middleware.js b/react/features/base/conference/middleware.js index 59c3cdcd0..c6006c44f 100644 --- a/react/features/base/conference/middleware.js +++ b/react/features/base/conference/middleware.js @@ -7,7 +7,7 @@ import { createPinnedEvent, sendAnalytics } from '../../analytics'; -import { CONNECTION_ESTABLISHED } from '../connection'; +import { CONNECTION_ESTABLISHED, CONNECTION_FAILED } from '../connection'; import { setVideoMuted, VIDEO_MUTISM_AUTHORITY } from '../media'; import { getLocalParticipant, @@ -20,6 +20,7 @@ import UIEvents from '../../../../service/UI/UIEvents'; import { TRACK_ADDED, TRACK_REMOVED } from '../tracks'; import { + conferenceFailed, conferenceLeft, createConference, setLastN, @@ -62,6 +63,9 @@ MiddlewareRegistry.register(store => next => action => { case CONNECTION_ESTABLISHED: return _connectionEstablished(store, next, action); + case CONNECTION_FAILED: + return _connectionFailed(store, next, action); + case DATA_CHANNEL_OPENED: return _syncReceiveVideoQuality(store, next, action); @@ -168,6 +172,62 @@ function _connectionEstablished({ dispatch }, next, action) { return result; } +/** + * Notifies the feature base/conference that the action + * {@code CONNECTION_FAILED} is being dispatched within a specific redux + * store. + * + * @param {Store} store - The redux store in which the specified {@code action} + * is being dispatched. + * @param {Dispatch} next - The redux {@code dispatch} function to dispatch the + * specified {@code action} to the specified {@code store}. + * @param {Action} action - The redux action {@code CONNECTION_FAILED} which is + * being dispatched in the specified {@code store}. + * @private + * @returns {Object} The value returned by {@code next(action)}. + */ +function _connectionFailed({ dispatch, getState }, next, action) { + const result = next(action); + + // FIXME: Workaround for the web version. Currently, the creation of the + // conference is handled by /conference.js and appropriate failure handlers + // are set there. + if (typeof APP === 'undefined') { + const { connection } = action; + const { error } = action; + + forEachConference(getState, conference => { + // It feels that it would make things easier if JitsiConference + // in lib-jitsi-meet would monitor it's connection and emit + // CONFERENCE_FAILED when it's dropped. It has more knowledge on + // whether it can recover or not. But because the reload screen + // and the retry logic is implemented in the app maybe it can be + // left this way for now. + if (conference.getConnection() === connection) { + // XXX Note that on mobile the error type passed to + // connectionFailed is always an object with .name property. + // This fact needs to be checked prior to enabling this logic on + // web. + const conferenceAction + = conferenceFailed(conference, error.name); + + // Copy the recoverable flag if set on the CONNECTION_FAILED + // action to not emit recoverable action caused by + // a non-recoverable one. + if (typeof error.recoverable !== 'undefined') { + conferenceAction.error.recoverable = error.recoverable; + } + + dispatch(conferenceAction); + } + + return true; + }); + } + + return result; +} + /** * Notifies the feature base/conference that the action {@code PIN_PARTICIPANT} * is being dispatched within a specific redux store. Pins the specified remote diff --git a/react/features/base/connection/reducer.js b/react/features/base/connection/reducer.js index fd50bd033..3d08176b2 100644 --- a/react/features/base/connection/reducer.js +++ b/react/features/base/connection/reducer.js @@ -57,7 +57,9 @@ ReducerRegistry.register( function _connectionDisconnected( state: Object, { connection }: { connection: Object }) { - if (state.connection !== connection) { + const connection_ = _getCurrentConnection(state); + + if (connection_ !== connection) { return state; } @@ -104,11 +106,7 @@ function _connectionFailed( connection: Object, error: ConnectionFailedError }) { - - // The current (similar to getCurrentConference in - // base/conference/functions.js) connection which is connecting or - // connected: - const connection_ = state.connection || state.connecting; + const connection_ = _getCurrentConnection(state); if (connection_ && connection_ !== connection) { return state; @@ -139,6 +137,11 @@ function _connectionWillConnect( { connection }: { connection: Object }) { return assign(state, { connecting: connection, + + // We don't care if the previous connection has been closed already, + // because it's an async process and there's no guarantee if it'll be + // done before the new one is established. + connection: undefined, error: undefined, passwordRequired: undefined }); @@ -188,6 +191,19 @@ function _constructOptions(locationURL: URL) { }; } +/** + * The current (similar to getCurrentConference in base/conference/functions.js) + * connection which is {@code connection} or {@code connecting}. + * + * @param {Object} baseConnectionState - The current state of the + * {@code 'base/connection'} feature. + * @returns {JitsiConnection} - The current {@code JitsiConnection} if any. + * @private + */ +function _getCurrentConnection(baseConnectionState: Object): ?Object { + return baseConnectionState.connection || baseConnectionState.connecting; +} + /** * Reduces a specific redux action {@link SET_LOCATION_URL} of the feature * base/connection. diff --git a/react/features/mobile/external-api/middleware.js b/react/features/mobile/external-api/middleware.js index 64ae1c241..6c0eda69e 100644 --- a/react/features/mobile/external-api/middleware.js +++ b/react/features/mobile/external-api/middleware.js @@ -189,9 +189,9 @@ function _sendConferenceEvent( /** * Sends {@link CONFERENCE_FAILED} event when the {@link CONNECTION_FAILED} - * occurs. Otherwise the external API will not emit such event, because at this - * point conference has not been created yet and the base/conference feature - * will not emit it. + * occurs. It should be done only if the connection fails before the conference + * instance is created. Otherwise the eventual failure event is supposed to be + * emitted by the base/conference feature. * * @param {Store} store - The redux store. * @param {Action} action - The redux action. @@ -199,8 +199,16 @@ function _sendConferenceEvent( */ function _sendConferenceFailedOnConnectionError(store, action) { const { locationURL } = store.getState()['features/base/connection']; + const { connection } = action; - locationURL && _sendEvent( + locationURL + && forEachConference( + store, + + // If there's any conference in the base/conference state then the + // base/conference feature is supposed to emit a failure. + conference => conference.getConnection() !== connection) + && _sendEvent( store, _getSymbolDescription(CONFERENCE_FAILED), /* data */ {