private async actionReconnect()

in src/audiovideocontroller/DefaultAudioVideoController.ts [1417:1498]


  private async actionReconnect(status: MeetingSessionStatus): Promise<void> {
    if (!this._reconnectController.hasStartedConnectionAttempt()) {
      this._reconnectController.startedConnectionAttempt(false);
      this.forEachObserver(observer => {
        Maybe.of(observer.audioVideoDidStartConnecting).map(f => f.bind(observer)(true));
      });
    }

    this.meetingSessionContext.volumeIndicatorAdapter.onReconnect();
    this.connectionHealthData.reset();
    this.receiveRemotePauseResumeTask = new ReceiveRemoteVideoPauseResume(
      this.meetingSessionContext
    );
    try {
      await new SerialGroupTask(this.logger, this.wrapTaskName('AudioVideoReconnect'), [
        new TimeoutTask(
          this.logger,
          new SerialGroupTask(this.logger, 'Media', [
            new CleanRestartedSessionTask(this.meetingSessionContext),
            new SerialGroupTask(this.logger, 'Signaling', [
              new OpenSignalingConnectionTask(this.meetingSessionContext),
              new JoinAndReceiveIndexTask(this.meetingSessionContext),
            ]),
            new CreatePeerConnectionTask(this.meetingSessionContext),
          ]),
          this.configuration.connectionTimeoutMs
        ),
        // TODO: Do we need ReceiveVideoInputTask in the reconnect operation?
        new ReceiveVideoInputTask(this.meetingSessionContext),
        new TimeoutTask(
          this.logger,
          new SerialGroupTask(this.logger, 'UpdateSession', [
            new AttachMediaInputTask(this.meetingSessionContext),
            new CreateSDPTask(this.meetingSessionContext),
            new SetLocalDescriptionTask(this.meetingSessionContext),
            new FinishGatheringICECandidatesTask(this.meetingSessionContext),
            new SubscribeAndReceiveSubscribeAckTask(this.meetingSessionContext),
            new SetRemoteDescriptionTask(this.meetingSessionContext),
            this.receiveRemotePauseResumeTask,
          ]),
          this.configuration.connectionTimeoutMs
        ),
      ]).run();

      this.sessionStateController.perform(SessionStateControllerAction.FinishConnecting, () => {
        /* istanbul ignore else */
        if (this.eventController) {
          const {
            signalingOpenDurationMs,
            poorConnectionCount,
            startTimeMs,
            iceGatheringDurationMs,
            attendeePresenceDurationMs,
            meetingStartDurationMs,
          } = this.meetingSessionContext;
          const attributes: AudioVideoEventAttributes = {
            maxVideoTileCount: this.meetingSessionContext.maxVideoTileCount,
            meetingDurationMs: Math.round(Date.now() - startTimeMs),
            meetingStatus: MeetingSessionStatusCode[status.statusCode()],
            signalingOpenDurationMs,
            iceGatheringDurationMs,
            attendeePresenceDurationMs,
            poorConnectionCount,
            meetingStartDurationMs,
            retryCount: this.totalRetryCount,
          };
          this.eventController.publishEvent('meetingReconnected', attributes);
        }
        this.actionFinishConnecting();
      });
    } catch (error) {
      // To perform the "Reconnect" action again, the session should be in the "Connected" state.
      this.sessionStateController.perform(SessionStateControllerAction.FinishConnecting, () => {
        this.logger.info('failed to reconnect audio-video session');
        const status = new MeetingSessionStatus(
          this.getMeetingStatusCode(error) || MeetingSessionStatusCode.TaskFailed
        );
        this.handleMeetingSessionStatus(status, error);
      });
    }
    this.connectionHealthData.setConnectionStartTime();
  }