in src/task/JoinAndReceiveIndexTask.ts [37:120]
async run(): Promise<void> {
const indexFrame = await new Promise<SdkIndexFrame>((resolve, reject) => {
const context = this.context;
context.turnCredentials = null;
class IndexFrameInterceptor implements SignalingClientObserver, TaskCanceler {
constructor(private signalingClient: SignalingClient) {}
cancel(): void {
this.signalingClient.removeObserver(this);
reject(new Error(`JoinAndReceiveIndexTask got canceled while waiting for SdkIndexFrame`));
}
handleSignalingClientEvent(event: SignalingClientEvent): void {
if (event.type === SignalingClientEventType.WebSocketClosed) {
let message = `The signaling connection was closed with code ${event.closeCode} and reason: ${event.closeReason}`;
context.logger.warn(message);
let statusCode: MeetingSessionStatusCode = MeetingSessionStatusCode.SignalingBadRequest;
if (event.closeCode === 4410) {
message = 'The meeting already ended.';
context.logger.warn(message);
statusCode = MeetingSessionStatusCode.MeetingEnded;
} else if (event.closeCode >= 4500 && event.closeCode < 4600) {
statusCode = MeetingSessionStatusCode.SignalingInternalServerError;
}
context.audioVideoController.handleMeetingSessionStatus(
new MeetingSessionStatus(statusCode),
new Error(message)
);
return;
}
if (event.type !== SignalingClientEventType.ReceivedSignalFrame) {
return;
}
if (event.message.type === SdkSignalFrame.Type.JOIN_ACK) {
// @ts-ignore: force cast to SdkJoinAckFrame
const joinAckFrame: SdkJoinAckFrame = event.message.joinack;
if (joinAckFrame && joinAckFrame.videoSubscriptionLimit) {
context.videoSubscriptionLimit = joinAckFrame.videoSubscriptionLimit;
}
if (joinAckFrame && joinAckFrame.turnCredentials) {
context.turnCredentials = new MeetingSessionTURNCredentials();
context.turnCredentials.username = joinAckFrame.turnCredentials.username;
context.turnCredentials.password = joinAckFrame.turnCredentials.password;
context.turnCredentials.ttl = joinAckFrame.turnCredentials.ttl;
context.turnCredentials.uris = joinAckFrame.turnCredentials.uris
.map((uri: string): string => {
return context.meetingSessionConfiguration.urls.urlRewriter(uri);
})
.filter((uri: string) => {
return !!uri;
});
} else {
context.logger.error('missing TURN credentials in JoinAckFrame');
}
return;
}
if (event.message.type !== SdkSignalFrame.Type.INDEX) {
return;
}
this.signalingClient.removeObserver(this);
// @ts-ignore: force cast to SdkIndexFrame
const indexFrame: SdkIndexFrame = event.message.index;
resolve(indexFrame);
}
}
const interceptor = new IndexFrameInterceptor(this.context.signalingClient);
this.context.signalingClient.registerObserver(interceptor);
this.taskCanceler = interceptor;
this.context.signalingClient.join(
new SignalingClientJoin(
this.maxVideos,
true,
this.context.meetingSessionConfiguration.applicationMetadata
)
);
});
this.context.logger.info(`received first index ${JSON.stringify(indexFrame)}`);
// We currently don't bother ingesting this into the same places as `ReceiveVideoStreamIndexTask` as we synchronously attempt a first subscribe
// after this task completes and the state isn't quite in the right place to make it work without some refactoring. However that
// means that we will always have an initial subscribe without any received videos.
this.context.indexFrame = indexFrame;
}