diff --git a/client/src/app/site/interaction/components/call/call.component.html b/client/src/app/site/interaction/components/call/call.component.html
index 5233fd94c..ee87ed83f 100644
--- a/client/src/app/site/interaction/components/call/call.component.html
+++ b/client/src/app/site/interaction/components/call/call.component.html
@@ -72,15 +72,17 @@
-
+
+
+
diff --git a/client/src/app/site/interaction/components/call/call.component.ts b/client/src/app/site/interaction/components/call/call.component.ts
index 00852e182..4b44badbe 100644
--- a/client/src/app/site/interaction/components/call/call.component.ts
+++ b/client/src/app/site/interaction/components/call/call.component.ts
@@ -38,6 +38,8 @@ export class CallComponent extends BaseViewComponentDirective implements OnInit,
public isJitsiActiveInAnotherTab: Observable = this.rtcService.inOtherTab;
public canEnterCall: Observable = this.callRestrictionService.canEnterCallObservable;
public isJitsiDialogOpen: Observable = this.rtcService.showCallDialogObservable;
+ public showParticles: Observable = this.applauseService.showParticles;
+ public hasLiveStreamUrl: Observable = this.streamService.hasLiveStreamUrlObvervable;
public isJitsiActive: boolean;
public isJoined: boolean;
@@ -64,18 +66,6 @@ export class CallComponent extends BaseViewComponentDirective implements OnInit,
return this.isJitsiActive && this.isJoined;
}
- public get showParticles(): Observable {
- return this.applauseService.showParticles;
- }
-
- public get canSeeLiveStream(): Observable {
- return this.streamService.canSeeLiveStreamObservable;
- }
-
- public get liveStreamUrl(): Observable {
- return this.streamService.liveStreamUrlObservable;
- }
-
private autoConnect: boolean;
@Output()
diff --git a/client/src/app/site/interaction/components/interaction-container/interaction-container.component.ts b/client/src/app/site/interaction/components/interaction-container/interaction-container.component.ts
index 6a8a50e44..67a9c60ba 100644
--- a/client/src/app/site/interaction/components/interaction-container/interaction-container.component.ts
+++ b/client/src/app/site/interaction/components/interaction-container/interaction-container.component.ts
@@ -1,4 +1,4 @@
-import { ChangeDetectionStrategy, ChangeDetectorRef, Component } from '@angular/core';
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Title } from '@angular/platform-browser';
@@ -18,7 +18,7 @@ import { StreamService } from '../../services/stream.service';
styleUrls: ['./interaction-container.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
-export class InteractionContainerComponent extends BaseViewComponentDirective {
+export class InteractionContainerComponent extends BaseViewComponentDirective implements OnInit {
public showBody = false;
private streamRunning = false;
@@ -63,11 +63,6 @@ export class InteractionContainerComponent extends BaseViewComponentDirective {
) {
super(titleService, translate, matSnackBar);
this.subscriptions.push(
- interactionService.conferenceStateObservable.pipe(distinctUntilChanged()).subscribe(state => {
- if (state) {
- this.clearTitles();
- }
- }),
rtcService.showCallDialogObservable.subscribe(show => {
if (show) {
this.showBody = false;
@@ -91,9 +86,20 @@ export class InteractionContainerComponent extends BaseViewComponentDirective {
);
}
+ public ngOnInit(): void {
+ this.subscriptions.push(
+ this.interactionService.conferenceStateObservable.pipe(distinctUntilChanged()).subscribe(state => {
+ if (state) {
+ this.clearTitles();
+ }
+ })
+ );
+ }
+
private clearTitles(): void {
this.containerHeadTitle = '';
this.containerHeadSubtitle = '';
+ this.cd.markForCheck();
this.cd.detectChanges();
}
@@ -104,14 +110,14 @@ export class InteractionContainerComponent extends BaseViewComponentDirective {
public updateTitle(title: string): void {
if (title !== this.containerHeadTitle) {
this.containerHeadTitle = title ?? '';
- this.cd.detectChanges();
+ this.cd.markForCheck();
}
}
public updateSubtitle(title: string): void {
if (title !== this.containerHeadSubtitle) {
this.containerHeadSubtitle = title ?? '';
- this.cd.detectChanges();
+ this.cd.markForCheck();
}
}
}
diff --git a/client/src/app/site/interaction/services/call-restriction.service.ts b/client/src/app/site/interaction/services/call-restriction.service.ts
index 7939ee764..d570232a9 100644
--- a/client/src/app/site/interaction/services/call-restriction.service.ts
+++ b/client/src/app/site/interaction/services/call-restriction.service.ts
@@ -88,7 +88,7 @@ export class CallRestrictionService {
) {
this.hasToEnterCallSubject.next();
}
- } else if (operatorClosIndex === UserListIndexType.NotOnList && this.restricted) {
+ } else if (operatorClosIndex === UserListIndexType.NotOnList && this.restricted && !this.canManageSpeaker) {
this.hasToLeaveCallSubject.next();
}
}
diff --git a/client/src/app/site/interaction/services/interaction.service.ts b/client/src/app/site/interaction/services/interaction.service.ts
index 98d0abe33..886aacfae 100644
--- a/client/src/app/site/interaction/services/interaction.service.ts
+++ b/client/src/app/site/interaction/services/interaction.service.ts
@@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';
-import { BehaviorSubject, Observable } from 'rxjs';
-import { map } from 'rxjs/operators';
+import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
+import { distinctUntilChanged, map } from 'rxjs/operators';
import { ConfigService } from 'app/core/ui-services/config.service';
import { CallRestrictionService } from './call-restriction.service';
@@ -9,9 +9,9 @@ import { RtcService } from './rtc.service';
import { StreamService } from './stream.service';
export enum ConferenceState {
- none,
- stream,
- jitsi
+ none = 1,
+ stream = 2,
+ jitsi = 3
}
@Injectable({
@@ -20,17 +20,14 @@ export enum ConferenceState {
export class InteractionService {
private conferenceStateSubject = new BehaviorSubject(ConferenceState.none);
public conferenceStateObservable = this.conferenceStateSubject.asObservable();
- public showLiveConfObservable: Observable;
+ public showLiveConfObservable: Observable = this.configService.get(
+ 'general_system_conference_show'
+ );
private get conferenceState(): ConferenceState {
return this.conferenceStateSubject.value;
}
- private isJitsiEnabled: boolean;
private isInCall: boolean;
- private isJitsiActive: boolean;
- private hasLiveStreamUrl: boolean;
- private canSeeLiveStream: boolean;
- private showLiveConf: boolean;
public get isConfStateStream(): Observable {
return this.conferenceStateObservable.pipe(map(state => state === ConferenceState.stream));
@@ -50,36 +47,38 @@ export class InteractionService {
private rtcService: RtcService,
private callRestrictionService: CallRestrictionService
) {
- this.showLiveConfObservable = this.configService.get('general_system_conference_show');
+ combineLatest(
+ this.showLiveConfObservable,
+ this.streamService.hasLiveStreamUrlObvervable,
+ this.streamService.canSeeLiveStreamObservable,
+ this.rtcService.isJitsiEnabledObservable,
+ this.rtcService.isJoinedObservable,
+ this.rtcService.isJitsiActiveObservable,
+ this.callRestrictionService.canEnterCallObservable,
+ (showConf, hasStreamUrl, canSeeStream, jitsiEnabled, inCall, jitsiActive, canEnterCall) => {
+ this.isInCall = inCall;
- /**
- * If you want to somehow simplify this using rxjs merge-map magic or something
- * be my guest.
- */
- this.streamService.liveStreamUrlObservable.subscribe(url => {
- this.hasLiveStreamUrl = !!url?.trim() ?? false;
- this.detectDeadState();
- });
-
- this.streamService.canSeeLiveStreamObservable.subscribe(canSee => {
- this.canSeeLiveStream = canSee;
- this.detectDeadState();
- });
-
- this.rtcService.isJitsiEnabledObservable.subscribe(enabled => {
- this.isJitsiEnabled = enabled;
- this.detectDeadState();
- });
-
- this.rtcService.isJoinedObservable.subscribe(joined => {
- this.isInCall = joined;
- this.detectDeadState();
- });
-
- this.rtcService.isJitsiActiveObservable.subscribe(isActive => {
- this.isJitsiActive = isActive;
- this.detectDeadState();
- });
+ /**
+ * most importantly, if there is a call, to not change the state here
+ */
+ if (inCall || jitsiActive) {
+ return;
+ }
+ if (hasStreamUrl && canSeeStream) {
+ return ConferenceState.stream;
+ } else if (showConf && jitsiEnabled && canEnterCall && (!hasStreamUrl || !canSeeStream)) {
+ return ConferenceState.jitsi;
+ } else {
+ return ConferenceState.none;
+ }
+ }
+ )
+ .pipe(distinctUntilChanged())
+ .subscribe(state => {
+ if (state) {
+ this.setConferenceState(state);
+ }
+ });
this.callRestrictionService.hasToEnterCallObservable.subscribe(() => {
if (!this.isInCall) {
@@ -91,13 +90,6 @@ export class InteractionService {
this.callRestrictionService.hasToLeaveCallObservable.subscribe(() => {
this.viewStream();
});
-
- this.showLiveConfObservable.subscribe(showConf => {
- this.showLiveConf = showConf;
- this.detectDeadState();
- });
-
- this.detectDeadState();
}
public async enterCall(): Promise {
@@ -117,37 +109,4 @@ export class InteractionService {
this.conferenceStateSubject.next(newState);
}
}
-
- /**
- * this is the "dead" state; you would see the jitsi state; but are not connected
- * or the connection is prohibited. If this occurs and a live stream
- * becomes available, switch to the stream state
- */
- private detectDeadState(): void {
- if (
- this.isInCall === undefined ||
- this.isJitsiActive === undefined ||
- this.hasLiveStreamUrl === undefined ||
- this.conferenceState === undefined ||
- this.canSeeLiveStream === undefined ||
- this.isJitsiEnabled === undefined
- ) {
- return;
- }
-
- /**
- * most importantly, if there is a call, to not change the state!
- */
- if (this.isInCall || this.isJitsiActive) {
- return;
- }
-
- if (this.hasLiveStreamUrl && this.canSeeLiveStream) {
- this.viewStream();
- } else if (this.showLiveConf && (!this.hasLiveStreamUrl || !this.canSeeLiveStream) && this.isJitsiEnabled) {
- this.enterCall();
- } else {
- this.setConferenceState(ConferenceState.none);
- }
- }
}
diff --git a/client/src/app/site/interaction/services/stream.service.ts b/client/src/app/site/interaction/services/stream.service.ts
index 61acf6d10..a15573db9 100644
--- a/client/src/app/site/interaction/services/stream.service.ts
+++ b/client/src/app/site/interaction/services/stream.service.ts
@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
import { StorageMap } from '@ngx-pwa/local-storage';
import { Observable, Subject } from 'rxjs';
-import { distinctUntilChanged } from 'rxjs/operators';
+import { distinctUntilChanged, map } from 'rxjs/operators';
import { OperatorService, Permission } from 'app/core/core-services/operator.service';
import { ConfigService } from 'app/core/ui-services/config.service';
@@ -13,7 +13,10 @@ const STREAM_RUNNING_STORAGE_KEY = 'streamIsRunning';
providedIn: 'root'
})
export class StreamService {
- public liveStreamUrlObservable: Observable;
+ public liveStreamUrlObservable: Observable = this.configService.get('general_system_stream_url');
+ public hasLiveStreamUrlObvervable: Observable = this.liveStreamUrlObservable.pipe(
+ map(url => !!url?.trim() || false)
+ );
/**
* undefined is controlled behavior, meaning, this property was not
@@ -28,9 +31,11 @@ export class StreamService {
private canSeeLiveStreamSubject = new Subject();
public canSeeLiveStreamObservable = this.canSeeLiveStreamSubject.asObservable();
- public constructor(private storageMap: StorageMap, operator: OperatorService, configService: ConfigService) {
- this.liveStreamUrlObservable = configService.get('general_system_stream_url');
-
+ public constructor(
+ private storageMap: StorageMap,
+ operator: OperatorService,
+ private configService: ConfigService
+ ) {
this.streamLoadedOnceObservable = this.storageMap
.watch(STREAM_RUNNING_STORAGE_KEY, { type: 'boolean' })
.pipe(distinctUntilChanged());