241 lines
7.1 KiB
TypeScript
241 lines
7.1 KiB
TypeScript
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
|
|
import { Router } from '@angular/router';
|
|
import { MatIcon } from '@angular/material/icon';
|
|
import {
|
|
RecordingDeleteRequestedEvent,
|
|
RecordingStartRequestedEvent,
|
|
RecordingStopRequestedEvent,
|
|
ApiDirectiveModule,
|
|
ParticipantLeftEvent,
|
|
ParticipantModel,
|
|
OpenViduComponentsUiModule,
|
|
ParticipantLeftReason
|
|
} from 'openvidu-components-angular';
|
|
|
|
import {
|
|
MeetChatPreferences,
|
|
MeetRecordingAccess,
|
|
MeetRecordingPreferences,
|
|
MeetVirtualBackgroundPreferences
|
|
} from '@lib/typings/ce';
|
|
|
|
import {
|
|
HttpService,
|
|
WebComponentManagerService,
|
|
ContextService,
|
|
RoomService,
|
|
SessionStorageService
|
|
} from '../../services';
|
|
import { OutboundEventMessage } from 'webcomponent/src/models/message.type';
|
|
import { WebComponentEvent } from 'webcomponent/src/models/event.model';
|
|
|
|
@Component({
|
|
selector: 'app-video-room',
|
|
templateUrl: './video-room.component.html',
|
|
styleUrls: ['./video-room.component.scss'],
|
|
standalone: true,
|
|
imports: [OpenViduComponentsUiModule, ApiDirectiveModule, MatIcon]
|
|
})
|
|
export class VideoRoomComponent implements OnInit, OnDestroy {
|
|
roomId = '';
|
|
participantName = '';
|
|
token = '';
|
|
serverError = '';
|
|
loading = true;
|
|
chatPreferences: MeetChatPreferences = { enabled: true };
|
|
recordingPreferences: MeetRecordingPreferences = {
|
|
enabled: true,
|
|
allowAccessTo: MeetRecordingAccess.ADMIN_MODERATOR_PUBLISHER
|
|
};
|
|
virtualBackgroundPreferences: MeetVirtualBackgroundPreferences = { enabled: true };
|
|
featureFlags = {
|
|
videoEnabled: true,
|
|
audioEnabled: true,
|
|
showMicrophone: true,
|
|
showCamera: true,
|
|
showScreenShare: true,
|
|
showPrejoin: true,
|
|
showChat: true,
|
|
showRecording: true,
|
|
showBackgrounds: true
|
|
};
|
|
|
|
constructor(
|
|
protected httpService: HttpService,
|
|
protected router: Router,
|
|
protected ctxService: ContextService,
|
|
protected roomService: RoomService,
|
|
protected wcManagerService: WebComponentManagerService,
|
|
protected sessionStorageService: SessionStorageService,
|
|
protected cdr: ChangeDetectorRef
|
|
) {}
|
|
|
|
async ngOnInit() {
|
|
try {
|
|
this.roomId = this.ctxService.getRoomId();
|
|
this.participantName = this.ctxService.getParticipantName();
|
|
|
|
if (this.ctxService.isEmbeddedMode()) {
|
|
this.featureFlags.showPrejoin = false;
|
|
}
|
|
|
|
// TODO: Apply room preferences from saved room using context service
|
|
// await this.loadRoomPreferences();
|
|
|
|
// TODO: Extract permissions from token and apply them to the component
|
|
this.applyParticipantPermissions();
|
|
} catch (error: any) {
|
|
console.error('Error fetching room preferences', error);
|
|
this.serverError = error.error.message || error.message || error.error;
|
|
}
|
|
this.loading = false;
|
|
}
|
|
|
|
ngOnDestroy(): void {
|
|
// Clean up the context service
|
|
// this.contextService.clearContext();
|
|
this.wcManagerService.stopCommandsListener();
|
|
}
|
|
|
|
async onTokenRequested(participantName: string) {
|
|
try {
|
|
if (this.ctxService.isStandaloneMode()) {
|
|
// As token is not provided, we need to set the participant name from
|
|
// ov-videoconference event
|
|
this.ctxService.setParticipantName(participantName);
|
|
}
|
|
|
|
this.token = this.ctxService.getToken();
|
|
} catch (error: any) {
|
|
console.error(error);
|
|
this.serverError = error.error;
|
|
}
|
|
|
|
this.loading = false;
|
|
this.cdr.detectChanges();
|
|
}
|
|
|
|
onParticipantConnected(event: ParticipantModel) {
|
|
const message: OutboundEventMessage = {
|
|
event: WebComponentEvent.JOIN,
|
|
payload: {
|
|
roomId: event.getProperties().room?.name || '',
|
|
participantName: event.name!
|
|
}
|
|
};
|
|
this.wcManagerService.sendMessageToParent(message);
|
|
}
|
|
|
|
onParticipantLeft(event: ParticipantLeftEvent) {
|
|
console.warn('Participant left the room. Redirecting to:');
|
|
const redirectURL = this.ctxService.getLeaveRedirectURL() || '/disconnected';
|
|
const isExternalURL = /^https?:\/\//.test(redirectURL);
|
|
const isRoomDeleted = event.reason === ParticipantLeftReason.ROOM_DELETED;
|
|
|
|
let message: OutboundEventMessage<WebComponentEvent.MEETING_ENDED | WebComponentEvent.LEFT>;
|
|
|
|
if (isRoomDeleted) {
|
|
message = {
|
|
event: WebComponentEvent.MEETING_ENDED,
|
|
payload: {
|
|
roomId: event.roomName
|
|
}
|
|
} as OutboundEventMessage<WebComponentEvent.MEETING_ENDED>;
|
|
} else {
|
|
message = {
|
|
event: WebComponentEvent.LEFT,
|
|
payload: {
|
|
roomId: event.roomName,
|
|
participantName: event.participantName,
|
|
reason: event.reason
|
|
}
|
|
} as OutboundEventMessage<WebComponentEvent.LEFT>;
|
|
}
|
|
|
|
this.wcManagerService.sendMessageToParent(message);
|
|
this.sessionStorageService.removeModeratorSecret(event.roomName);
|
|
|
|
//if (this.contextService.isEmbeddedMode()) this.sendMessageToParent(event);
|
|
this.redirectTo(redirectURL, isExternalURL);
|
|
|
|
// Stop listening to commands from the parent
|
|
this.wcManagerService.stopCommandsListener();
|
|
}
|
|
|
|
async onRecordingStartRequested(event: RecordingStartRequestedEvent) {
|
|
try {
|
|
const { roomName: roomId } = event;
|
|
await this.httpService.startRecording(roomId);
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
}
|
|
|
|
async onRecordingStopRequested(event: RecordingStopRequestedEvent) {
|
|
try {
|
|
const { recordingId } = event;
|
|
|
|
if (!recordingId) throw new Error('Recording ID not found when stopping recording');
|
|
|
|
await this.httpService.stopRecording(recordingId);
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
}
|
|
|
|
async onRecordingDeleteRequested(event: RecordingDeleteRequestedEvent) {
|
|
try {
|
|
const { recordingId } = event;
|
|
|
|
if (!recordingId) throw new Error('Recording ID not found when deleting recording');
|
|
|
|
await this.httpService.deleteRecording(recordingId);
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Loads the room preferences from the global preferences service and assigns them to the component.
|
|
*
|
|
* This method fetches the room preferences asynchronously and updates the component's properties
|
|
* based on the fetched preferences. It also updates the UI flags to show or hide certain features
|
|
* like chat, recording, and activity panel based on the preferences.
|
|
*
|
|
* @returns {Promise<void>} A promise that resolves when the room preferences have been loaded and applied.
|
|
*/
|
|
private async loadRoomPreferences() {
|
|
const preferences = await this.roomService.getRoomPreferences();
|
|
// Assign the preferences to the component
|
|
Object.assign(this, preferences);
|
|
|
|
this.featureFlags.showChat = this.chatPreferences.enabled;
|
|
this.featureFlags.showRecording = this.recordingPreferences.enabled;
|
|
this.featureFlags.showBackgrounds = this.virtualBackgroundPreferences.enabled;
|
|
}
|
|
|
|
/**
|
|
* Configures the feature flags based on the token permissions.
|
|
*
|
|
* This method checks the token permissions and sets the feature flags accordingly.
|
|
*/
|
|
private applyParticipantPermissions() {
|
|
if (this.featureFlags.showChat) {
|
|
this.featureFlags.showChat = this.ctxService.canChat();
|
|
}
|
|
if (this.featureFlags.showRecording) {
|
|
this.featureFlags.showRecording = this.ctxService.canRecord();
|
|
}
|
|
}
|
|
|
|
private redirectTo(url: string, isExternal: boolean) {
|
|
if (isExternal) {
|
|
console.log('Redirecting to external URL:', url);
|
|
window.location.href = url;
|
|
} else {
|
|
console.log('Redirecting to internal route:', url);
|
|
this.router.navigate([url], { replaceUrl: true });
|
|
}
|
|
}
|
|
}
|