You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

IceFailedHandling.ts 4.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import { getLogger } from '@jitsi/logger';
  2. import JitsiConference from '../../JitsiConference';
  3. import * as JitsiConferenceErrors from '../../JitsiConferenceErrors';
  4. import * as JitsiConferenceEvents from '../../JitsiConferenceEvents';
  5. const logger = getLogger(__filename);
  6. /**
  7. * This class deals with shenanigans around JVB media session's ICE failed status handling.
  8. *
  9. * If ICE connection is not re-established within 2 secs after the internet comes back online, the client will initiate
  10. * a session restart via 'session-terminate'. This results in Jicofo re-inviting the participant into the conference by
  11. * recreating the jvb media session so that there is minimla disruption to the user by default. However, if the
  12. * 'enableForcedReload' option is set in config.js, the conference will be forcefully reloaded.
  13. */
  14. export default class IceFailedHandling {
  15. private _conference: JitsiConference;
  16. private _canceled: boolean = false;
  17. private _iceFailedTimeout?: number;
  18. /**
  19. * Creates new {@code DelayedIceFailed} task.
  20. * @param {JitsiConference} conference
  21. */
  22. constructor(conference: JitsiConference) {
  23. this._conference = conference;
  24. }
  25. /**
  26. * After making sure there's no way for the ICE connection to recover this method either sends ICE failed
  27. * notification to Jicofo or emits the ice failed conference event.
  28. * @private
  29. * @returns {void}
  30. */
  31. _actOnIceFailed(): void {
  32. if (!this._conference.room) {
  33. return;
  34. }
  35. const { enableForcedReload } = this._conference.options.config;
  36. logger.info(`ICE failed, enableForcedReload: ${enableForcedReload}`);
  37. if (enableForcedReload) {
  38. logger.info('ICE failed, force reloading the conference');
  39. this._conference.eventEmitter.emit(
  40. JitsiConferenceEvents.CONFERENCE_FAILED,
  41. JitsiConferenceErrors.CONFERENCE_RESTARTED);
  42. return;
  43. }
  44. const jvbConnection = this._conference.jvbJingleSession;
  45. const jvbConnIceState = jvbConnection?.getIceConnectionState();
  46. if (!jvbConnection) {
  47. logger.warn('Not sending ICE failed - no JVB connection');
  48. } else if (jvbConnIceState === 'connected') {
  49. logger.info('ICE connection restored - not sending ICE failed');
  50. } else {
  51. logger.info(`Sending ICE failed - the connection did not recover, ICE state: ${jvbConnIceState}`);
  52. this._conference._stopJvbSession({
  53. reason: 'connectivity-error',
  54. reasonDescription: 'ICE FAILED',
  55. requestRestart: true,
  56. sendSessionTerminate: true
  57. });
  58. }
  59. }
  60. /**
  61. * Starts the task.
  62. * @returns {void}
  63. */
  64. start(): void {
  65. // Using xmpp.ping allows to handle both XMPP being disconnected and internet offline cases. The ping function
  66. // uses sendIQ2 method which is resilient to XMPP connection disconnected state and will patiently wait until it
  67. // gets reconnected.
  68. // This also handles the case about waiting for the internet to come back online, because ping
  69. // will only succeed when the internet is online and then there's a chance for the ICE to recover from FAILED to
  70. // CONNECTED which is the extra 2 second timeout after ping.
  71. // The 65 second timeout is given on purpose as there's no chance for XMPP to recover after 65 seconds of no
  72. // communication with the server. Such resume attempt will result in unrecoverable conference failed event due
  73. // to 'item-not-found' error returned by the server.
  74. this._conference.xmpp.ping(65000).then(
  75. () => {
  76. if (!this._canceled) {
  77. this._iceFailedTimeout = window.setTimeout(() => {
  78. this._iceFailedTimeout = undefined;
  79. this._actOnIceFailed();
  80. }, 2000);
  81. }
  82. },
  83. error => {
  84. logger.error('PING error/timeout - not sending ICE failed', error);
  85. });
  86. }
  87. /**
  88. * Cancels the task.
  89. * @returns {void}
  90. */
  91. cancel(): void {
  92. this._canceled = true;
  93. window.clearTimeout(this._iceFailedTimeout);
  94. }
  95. }