mirror of https://github.com/OpenVidu/openvidu.git
ov-components: enhance participant name handling with preferred name resolution and fallback logic
parent
a3eaeee003
commit
b08ae47b34
|
|
@ -1,6 +1,6 @@
|
|||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { ParticipantService } from '../../../services/participant/participant.service';
|
||||
import { OpenViduService } from '../../../services/openvidu/openvidu.service';
|
||||
import { StorageService } from '../../../services/storage/storage.service';
|
||||
|
||||
/**
|
||||
|
|
@ -14,7 +14,6 @@ import { StorageService } from '../../../services/storage/storage.service';
|
|||
})
|
||||
export class ParticipantNameInputComponent implements OnInit {
|
||||
name: string;
|
||||
localParticipantSubscription: Subscription;
|
||||
@Input() isPrejoinPage: boolean;
|
||||
@Input() error: boolean;
|
||||
@Output() onNameUpdated = new EventEmitter<string>();
|
||||
|
|
@ -22,15 +21,15 @@ export class ParticipantNameInputComponent implements OnInit {
|
|||
|
||||
constructor(
|
||||
private participantService: ParticipantService,
|
||||
private openviduService: OpenViduService,
|
||||
private storageSrv: StorageService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.subscribeToParticipantProperties();
|
||||
const myName = this.participantService.getMyName();
|
||||
const storedName = this.storageSrv.getParticipantName();
|
||||
|
||||
this.name = myName ?? storedName ?? this.generateRandomName();
|
||||
this.name = myName ?? storedName ?? this.openviduService.generateFallbackParticipantName();
|
||||
|
||||
if (!myName && !storedName) {
|
||||
this.storageSrv.setParticipantName(this.name);
|
||||
|
|
@ -63,16 +62,4 @@ export class ParticipantNameInputComponent implements OnInit {
|
|||
this.onEnterPressed.emit();
|
||||
}
|
||||
}
|
||||
|
||||
private subscribeToParticipantProperties() {
|
||||
// this.localParticipantSubscription = this.participantService.localParticipant$.subscribe((p: ParticipantModel | undefined) => {
|
||||
// if (p) {
|
||||
// this.name = p.name;
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
private generateRandomName(): string {
|
||||
return 'OpenVidu_User_' + Math.floor(Math.random() * 100);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -928,9 +928,7 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit {
|
|||
// Always initialize the room when ready to join
|
||||
this.openviduService.initRoom();
|
||||
|
||||
// Get the most current participant name from the service
|
||||
// This ensures we have the latest value after any batch updates
|
||||
const participantName = this.libService.getCurrentParticipantName() || this.latestParticipantName;
|
||||
const participantName = this.openviduService.ensurePreferredLocalParticipantName();
|
||||
|
||||
if (this.componentState.isRoomReady) {
|
||||
// Room is ready, hide prejoin and proceed
|
||||
|
|
@ -941,22 +939,8 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit {
|
|||
});
|
||||
} else {
|
||||
// Room not ready, request token if we have a participant name
|
||||
if (participantName) {
|
||||
this.log.d(`Requesting token for participant: ${participantName}`);
|
||||
this.onTokenRequested.emit(participantName);
|
||||
} else {
|
||||
this.log.w('No participant name available when requesting token');
|
||||
// Wait a bit and try again in case name is still propagating
|
||||
setTimeout(() => {
|
||||
const retryName = this.libService.getCurrentParticipantName() || this.latestParticipantName;
|
||||
if (retryName) {
|
||||
this.log.d(`Retrying token request for participant: ${retryName}`);
|
||||
this.onTokenRequested.emit(retryName);
|
||||
} else {
|
||||
this.log.e('Still no participant name available after retry');
|
||||
}
|
||||
}, 10);
|
||||
}
|
||||
this.log.d(`Requesting token for participant: ${participantName}`);
|
||||
this.onTokenRequested.emit(participantName);
|
||||
}
|
||||
|
||||
// Emit onReadyToJoin event only if prejoin page was actually shown
|
||||
|
|
@ -1081,12 +1065,8 @@ export class VideoconferenceComponent implements OnDestroy, AfterViewInit {
|
|||
// Add safety timeout in case name never arrives
|
||||
setTimeout(() => {
|
||||
if (!this.latestParticipantName) {
|
||||
this.log.w('No participant name received after timeout, proceeding anyway');
|
||||
const storedName = this.storageSrv.getParticipantName();
|
||||
if (storedName) {
|
||||
this.latestParticipantName = storedName;
|
||||
this.libService.updateGeneralConfig({ participantName: storedName });
|
||||
}
|
||||
this.log.w('No participant name received after timeout, using fallback');
|
||||
this.latestParticipantName = this.openviduService.ensurePreferredLocalParticipantName();
|
||||
this._onReadyToJoin();
|
||||
}
|
||||
}, VideoconferenceComponent.PARTICIPANT_NAME_TIMEOUT_MS);
|
||||
|
|
|
|||
|
|
@ -536,9 +536,7 @@ export class ParticipantNameDirective implements AfterViewInit, OnDestroy {
|
|||
* @ignore
|
||||
*/
|
||||
update(participantName: string) {
|
||||
if (participantName) {
|
||||
this.libService.updateGeneralConfig({ participantName });
|
||||
}
|
||||
this.libService.updateGeneralConfig({ participantName: participantName?.trim() || '' });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -84,6 +84,12 @@ export interface ParticipantTrackPublication extends TrackPublication {
|
|||
* Interface defining properties of a participant.
|
||||
*/
|
||||
export interface ParticipantProperties {
|
||||
/**
|
||||
* Resolves the preferred display name for the participant.
|
||||
* Used for local participants where the directive/token/storage priority must override SDK defaults.
|
||||
*/
|
||||
preferredNameResolver?: () => string | undefined;
|
||||
|
||||
/**
|
||||
* The participant instance, which can be either a local participant or a remote participant.
|
||||
*/
|
||||
|
|
@ -134,10 +140,12 @@ export class ParticipantModel {
|
|||
private customVideoTrack: Partial<ParticipantTrackPublication>;
|
||||
private _hasEncryptionError: boolean = false;
|
||||
private _decryptedName: string | undefined;
|
||||
private _preferredNameResolver: (() => string | undefined) | undefined;
|
||||
private _fallbackName: string | undefined;
|
||||
|
||||
constructor(props: ParticipantProperties) {
|
||||
this.participant = props.participant;
|
||||
this._preferredNameResolver = props.preferredNameResolver;
|
||||
this._fallbackName = props.fallbackName?.trim() || undefined;
|
||||
this.colorProfile = props.colorProfile ?? `hsl(${Math.random() * 360}, 100%, 80%)`;
|
||||
this.room = props.room;
|
||||
|
|
@ -178,7 +186,13 @@ export class ParticipantModel {
|
|||
* @returns string
|
||||
*/
|
||||
get name(): string | undefined {
|
||||
return this._decryptedName?.trim() || this.participant.name?.trim() || this._fallbackName || this.participant.identity;
|
||||
return (
|
||||
this._decryptedName?.trim() ||
|
||||
this._preferredNameResolver?.()?.trim() ||
|
||||
this.participant.name?.trim() ||
|
||||
this._fallbackName ||
|
||||
this.participant.identity
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -318,6 +332,7 @@ export class ParticipantModel {
|
|||
*/
|
||||
getProperties(): ParticipantProperties {
|
||||
return {
|
||||
preferredNameResolver: this._preferredNameResolver,
|
||||
participant: this.participant,
|
||||
fallbackName: this._fallbackName,
|
||||
room: this.room,
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ import { StorageService } from '../storage/storage.service';
|
|||
providedIn: 'root'
|
||||
})
|
||||
export class OpenViduService {
|
||||
private static readonly FALLBACK_PARTICIPANT_PREFIX = 'Participant';
|
||||
|
||||
/*
|
||||
* @internal
|
||||
*/
|
||||
|
|
@ -56,6 +58,7 @@ export class OpenViduService {
|
|||
private localTracks: LocalTrack[] = [];
|
||||
private livekitToken = '';
|
||||
private livekitUrl = '';
|
||||
private tokenParticipantName: string | undefined;
|
||||
private log: ILogger;
|
||||
|
||||
/**
|
||||
|
|
@ -202,8 +205,9 @@ export class OpenViduService {
|
|||
await this.room.connect(this.livekitUrl, this.livekitToken);
|
||||
this.log.d(`Successfully connected to room ${this.room.name}`);
|
||||
|
||||
const participantName = this.storageService.getParticipantName();
|
||||
const participantName = this.getPreferredLocalParticipantName();
|
||||
if (participantName) {
|
||||
this.storageService.setParticipantName(participantName);
|
||||
this.room.localParticipant.setName(participantName);
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
@ -256,6 +260,41 @@ export class OpenViduService {
|
|||
return this.room?.name;
|
||||
}
|
||||
|
||||
getPreferredLocalParticipantName(): string | undefined {
|
||||
return (
|
||||
this.configService.getCurrentParticipantName()?.trim() ||
|
||||
this.tokenParticipantName ||
|
||||
this.storageService.getParticipantName()?.trim() ||
|
||||
undefined
|
||||
);
|
||||
}
|
||||
|
||||
ensurePreferredLocalParticipantName(): string {
|
||||
return this.getPreferredLocalParticipantName() || this.createFallbackParticipantName();
|
||||
}
|
||||
|
||||
generateFallbackParticipantName(): string {
|
||||
return `${OpenViduService.FALLBACK_PARTICIPANT_PREFIX}_${this.generateRandomSuffix()}`;
|
||||
}
|
||||
|
||||
private generateRandomSuffix(length: number = 6): string {
|
||||
return Math.random()
|
||||
.toString(36)
|
||||
.slice(2, 2 + length)
|
||||
.padEnd(length, '0');
|
||||
}
|
||||
|
||||
private createFallbackParticipantName(): string {
|
||||
const storedParticipantName = this.storageService.getParticipantName()?.trim();
|
||||
if (storedParticipantName) {
|
||||
return storedParticipantName;
|
||||
}
|
||||
|
||||
const fallbackName = this.generateFallbackParticipantName();
|
||||
this.storageService.setParticipantName(fallbackName);
|
||||
return fallbackName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if local participant is connected to the room
|
||||
* @returns
|
||||
|
|
@ -279,11 +318,15 @@ export class OpenViduService {
|
|||
const { livekitUrl: urlFromToken, participantName: participantNameFromToken } = this.extractLivekitData(token);
|
||||
|
||||
this.livekitToken = token;
|
||||
this.tokenParticipantName = participantNameFromToken;
|
||||
const url = livekitUrl || urlFromToken;
|
||||
const currentParticipantName = this.configService.getCurrentParticipantName() || this.storageService.getParticipantName() || undefined;
|
||||
if (participantNameFromToken && participantNameFromToken !== currentParticipantName) {
|
||||
this.storageService.setParticipantName(participantNameFromToken);
|
||||
const currentParticipantName = this.configService.getCurrentParticipantName()?.trim() || undefined;
|
||||
const storedParticipantName = this.storageService.getParticipantName()?.trim() || undefined;
|
||||
if (participantNameFromToken && !currentParticipantName) {
|
||||
this.configService.updateGeneralConfig({ participantName: participantNameFromToken });
|
||||
if (!storedParticipantName) {
|
||||
this.storageService.setParticipantName(participantNameFromToken);
|
||||
}
|
||||
}
|
||||
|
||||
if (!url) {
|
||||
|
|
|
|||
|
|
@ -99,8 +99,13 @@ export class ParticipantService {
|
|||
*/
|
||||
setLocalParticipant(participant: LocalParticipant) {
|
||||
const room = this.openviduService.getRoom();
|
||||
const fallbackName = this.directiveService.getCurrentParticipantName() || this.storageSrv.getParticipantName() || undefined;
|
||||
this.localParticipant = this.newParticipant({ participant, room, fallbackName });
|
||||
const fallbackName = this.storageSrv.getParticipantName() || undefined;
|
||||
this.localParticipant = this.newParticipant({
|
||||
participant,
|
||||
room,
|
||||
fallbackName,
|
||||
preferredNameResolver: () => this.openviduService.getPreferredLocalParticipantName()
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue