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();
}