ov-components: migrate to Angular signals for local and remote participants

master
Carlos Santos 2025-12-22 13:20:58 +01:00
parent 1b9162b6e5
commit f300788c1e
1 changed files with 34 additions and 27 deletions

View File

@ -1,12 +1,5 @@
import { Injectable, Signal } from '@angular/core'; import { Injectable, Signal, WritableSignal, signal } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop'; import { toObservable } from '@angular/core/rxjs-interop';
import { BehaviorSubject, Observable } from 'rxjs';
import { ILogger } from '../../models/logger.model';
import { ParticipantModel, ParticipantProperties } from '../../models/participant.model';
import { OpenViduComponentsConfigService } from '../config/directive-config.service';
import { GlobalConfigService } from '../config/global-config.service';
import { LoggerService } from '../logger/logger.service';
import { import {
AudioCaptureOptions, AudioCaptureOptions,
DataPublishOptions, DataPublishOptions,
@ -19,7 +12,13 @@ import {
VideoCaptureOptions, VideoCaptureOptions,
VideoPresets VideoPresets
} from 'livekit-client'; } from 'livekit-client';
import { Observable } from 'rxjs';
import { ILogger } from '../../models/logger.model';
import { ParticipantModel, ParticipantProperties } from '../../models/participant.model';
import { OpenViduComponentsConfigService } from '../config/directive-config.service';
import { GlobalConfigService } from '../config/global-config.service';
import { E2eeService } from '../e2ee/e2ee.service'; import { E2eeService } from '../e2ee/e2ee.service';
import { LoggerService } from '../logger/logger.service';
import { OpenViduService } from '../openvidu/openvidu.service'; import { OpenViduService } from '../openvidu/openvidu.service';
import { StorageService } from '../storage/storage.service'; import { StorageService } from '../storage/storage.service';
@ -32,16 +31,12 @@ export class ParticipantService {
* @deprecated Please prefer `localParticipantSignal` for reactive updates and `localParticipant$` when using RxJS. * @deprecated Please prefer `localParticipantSignal` for reactive updates and `localParticipant$` when using RxJS.
*/ */
localParticipant$: Observable<ParticipantModel | undefined>; localParticipant$: Observable<ParticipantModel | undefined>;
private localParticipantBS: BehaviorSubject<ParticipantModel | undefined> = new BehaviorSubject<ParticipantModel | undefined>(
undefined
);
/** /**
* Remote participants Observable which pushes the remote participants array in every update. * Remote participants Observable which pushes the remote participants array in every update.
* @deprecated Please prefer `remoteParticipantsSignal` for reactive updates and `remoteParticipants$` when using RxJS. * @deprecated Please prefer `remoteParticipantsSignal` for reactive updates and `remoteParticipants$` when using RxJS.
*/ */
remoteParticipants$: Observable<ParticipantModel[]>; remoteParticipants$: Observable<ParticipantModel[]>;
private remoteParticipantsBS: BehaviorSubject<ParticipantModel[]> = new BehaviorSubject<ParticipantModel[]>([]);
/** /**
* Local participant Signal for reactive programming with Angular signals. * Local participant Signal for reactive programming with Angular signals.
@ -49,6 +44,7 @@ export class ParticipantService {
* @since Angular 16+ * @since Angular 16+
*/ */
localParticipantSignal: Signal<ParticipantModel | undefined>; localParticipantSignal: Signal<ParticipantModel | undefined>;
private localParticipantWritableSignal: WritableSignal<ParticipantModel | undefined> = signal<ParticipantModel | undefined>(undefined);
/** /**
* Remote participants Signal for reactive programming with Angular signals. * Remote participants Signal for reactive programming with Angular signals.
@ -56,6 +52,7 @@ export class ParticipantService {
* @since Angular 16+ * @since Angular 16+
*/ */
remoteParticipantsSignal: Signal<ParticipantModel[]>; remoteParticipantsSignal: Signal<ParticipantModel[]>;
private remoteParticipantsWritableSignal: WritableSignal<ParticipantModel[]> = signal<ParticipantModel[]>([]);
private localParticipant: ParticipantModel | undefined; private localParticipant: ParticipantModel | undefined;
private remoteParticipants: ParticipantModel[] = []; private remoteParticipants: ParticipantModel[] = [];
@ -73,12 +70,14 @@ export class ParticipantService {
private e2eeService: E2eeService private e2eeService: E2eeService
) { ) {
this.log = this.loggerSrv.get('ParticipantService'); this.log = this.loggerSrv.get('ParticipantService');
this.localParticipant$ = this.localParticipantBS.asObservable();
this.remoteParticipants$ = this.remoteParticipantsBS.asObservable();
// Create signals from observables for modern reactive programming // Expose readonly signals
this.localParticipantSignal = toSignal(this.localParticipant$, { initialValue: undefined }); this.localParticipantSignal = this.localParticipantWritableSignal.asReadonly();
this.remoteParticipantsSignal = toSignal(this.remoteParticipants$, { initialValue: [] }); this.remoteParticipantsSignal = this.remoteParticipantsWritableSignal.asReadonly();
// Create Observables from signals for backward compatibility
this.localParticipant$ = toObservable(this.localParticipantWritableSignal);
this.remoteParticipants$ = toObservable(this.remoteParticipantsWritableSignal);
} }
/** /**
@ -87,8 +86,8 @@ export class ParticipantService {
clear(): void { clear(): void {
this.localParticipant = undefined; this.localParticipant = undefined;
this.remoteParticipants = []; this.remoteParticipants = [];
this.localParticipantBS.next(undefined); this.localParticipantWritableSignal.set(undefined);
this.remoteParticipantsBS.next([]); this.remoteParticipantsWritableSignal.set([]);
} }
/** /**
@ -342,7 +341,7 @@ export class ParticipantService {
*/ */
toggleMyVideoPinned(sid: string | undefined) { toggleMyVideoPinned(sid: string | undefined) {
if (sid && this.localParticipant) this.localParticipant.toggleVideoPinned(sid); if (sid && this.localParticipant) this.localParticipant.toggleVideoPinned(sid);
// this.updateLocalParticipant(); this.updateLocalParticipant();
} }
/** /**
@ -404,11 +403,17 @@ export class ParticipantService {
* Forces to update the local participant object and fire a new `localParticipant$` Observable event. * Forces to update the local participant object and fire a new `localParticipant$` Observable event.
*/ */
updateLocalParticipant() { updateLocalParticipant() {
// this._localParticipant.next( // Update Signal - create new reference to trigger reactivity
// Object.assign(Object.create(Object.getPrototypeOf(this.localParticipant)), { ...this.localParticipant }) // The Observable will automatically emit via toObservable()
// ); if (this.localParticipant) {
const updatedParticipant = Object.assign(
this.localParticipantBS.next(this.localParticipant); Object.create(Object.getPrototypeOf(this.localParticipant)),
{ ...this.localParticipant }
);
this.localParticipantWritableSignal.set(updatedParticipant);
} else {
this.localParticipantWritableSignal.set(undefined);
}
} }
/** /**
@ -478,7 +483,9 @@ export class ParticipantService {
* Force to update the remote participants object and fire a new `remoteParticipants$` Observable event. * Force to update the remote participants object and fire a new `remoteParticipants$` Observable event.
*/ */
updateRemoteParticipants() { updateRemoteParticipants() {
this.remoteParticipantsBS.next([...this.remoteParticipants]); // Update Signal - create new array reference to trigger reactivity
// The Observable will automatically emit via toObservable()
this.remoteParticipantsWritableSignal.set([...this.remoteParticipants]);
} }
/** /**