From c8264fdb1b3901b499352f0284dfaf675d126a65 Mon Sep 17 00:00:00 2001 From: csantosm <4a.santos@gmail.com> Date: Thu, 16 Jun 2022 14:01:07 +0200 Subject: [PATCH] openvidu-components: Added settings panel for configuring media devices --- .../activities-panel.component.ts | 6 +- .../lib/components/panel/panel.component.html | 5 + .../lib/components/panel/panel.component.ts | 44 +++++--- .../settings-panel.component.css | 29 +++++ .../settings-panel.component.html | 43 ++++++++ .../settings-panel.component.spec.ts | 25 +++++ .../settings-panel.component.ts | 20 ++++ .../pre-join/pre-join.component.css | 66 ------------ .../pre-join/pre-join.component.html | 100 ++--------------- .../components/pre-join/pre-join.component.ts | 98 ----------------- .../components/session/session.component.css | 32 +++++- .../components/session/session.component.html | 3 +- .../components/session/session.component.ts | 70 +++++++++--- .../audio-devices/audio-devices.component.css | 17 +++ .../audio-devices.component.html | 26 +++++ .../audio-devices.component.spec.ts | 25 +++++ .../audio-devices/audio-devices.component.ts | 80 ++++++++++++++ .../lang-selector/lang-selector.component.css | 4 + .../lang-selector.component.html | 9 ++ .../lang-selector.component.spec.ts | 25 +++++ .../lang-selector/lang-selector.component.ts | 26 +++++ .../nickname-input.component.css | 21 ++++ .../nickname-input.component.html | 16 +++ .../nickname-input.component.spec.ts | 25 +++++ .../nickname-input.component.ts | 36 +++++++ .../video-devices/video-devices.component.css | 25 +++++ .../video-devices.component.html | 24 +++++ .../video-devices.component.spec.ts | 25 +++++ .../video-devices/video-devices.component.ts | 102 ++++++++++++++++++ .../lib/components/stream/stream.component.ts | 4 +- .../components/toolbar/toolbar.component.css | 23 ++-- .../components/toolbar/toolbar.component.html | 8 ++ .../components/toolbar/toolbar.component.ts | 48 ++++++--- .../videoconference.component.html | 4 + .../videoconference.component.ts | 2 +- .../directives/api/api.directive.module.ts | 5 +- .../lib/directives/api/stream.directive.ts | 4 +- .../lib/directives/api/toolbar.directive.ts | 59 ++++++++++ .../template/openvidu-angular.directive.ts | 2 +- .../openvidu-angular/src/lib/lang/cn.json | 8 ++ .../openvidu-angular/src/lib/lang/de.json | 10 +- .../openvidu-angular/src/lib/lang/en.json | 8 ++ .../openvidu-angular/src/lib/lang/es.json | 8 ++ .../openvidu-angular/src/lib/lang/fr.json | 8 ++ .../openvidu-angular/src/lib/lang/hi.json | 8 ++ .../openvidu-angular/src/lib/lang/it.json | 8 ++ .../openvidu-angular/src/lib/lang/ja.json | 8 ++ .../openvidu-angular/src/lib/lang/nl.json | 8 ++ .../openvidu-angular/src/lib/lang/pt.json | 8 ++ .../src/lib/models/panel.model.ts | 3 +- .../src/lib/models/participant.model.ts | 27 +++-- .../src/lib/openvidu-angular.module.ts | 11 ++ .../config/openvidu-angular.config.service.ts | 12 ++- .../src/lib/services/device/device.service.ts | 11 +- .../lib/services/openvidu/openvidu.service.ts | 4 + .../src/lib/services/panel/panel.service.ts | 61 ++++++----- .../participant/participant.service.ts | 2 +- .../openvidu-angular/src/public-api.ts | 1 + 58 files changed, 1029 insertions(+), 371 deletions(-) create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.css create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.html create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.spec.ts create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.ts create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/audio-devices/audio-devices.component.css create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/audio-devices/audio-devices.component.html create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/audio-devices/audio-devices.component.spec.ts create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/audio-devices/audio-devices.component.ts create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/lang-selector/lang-selector.component.css create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/lang-selector/lang-selector.component.html create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/lang-selector/lang-selector.component.spec.ts create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/lang-selector/lang-selector.component.ts create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/nickname-input/nickname-input.component.css create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/nickname-input/nickname-input.component.html create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/nickname-input/nickname-input.component.spec.ts create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/nickname-input/nickname-input.component.ts create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/video-devices/video-devices.component.css create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/video-devices/video-devices.component.html create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/video-devices/video-devices.component.spec.ts create mode 100644 openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/video-devices/video-devices.component.ts diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/activities-panel.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/activities-panel.component.ts index 85afdbb7..9c22a5d3 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/activities-panel.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/activities-panel/activities-panel.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit, Output, EventEmitter, ChangeDetectionStrategy, Chang import { Subscription } from 'rxjs'; import { PanelType } from '../../../models/panel.model'; import { OpenViduAngularConfigService } from '../../../services/config/openvidu-angular.config.service'; -import { PanelService } from '../../../services/panel/panel.service'; +import { PanelEvent, PanelService } from '../../../services/panel/panel.service'; @Component({ selector: 'ov-activities-panel', @@ -114,8 +114,8 @@ export class ActivitiesPanelComponent implements OnInit { private subscribeToPanelToggling() { this.panelSubscription = this.panelService.panelOpenedObs.subscribe( - (ev: { opened: boolean; type?: PanelType | string; expand?: string }) => { - if (ev.type === PanelType.ACTIVITIES) { + (ev: PanelEvent) => { + if (ev.type === PanelType.ACTIVITIES && !!ev.expand) { this.expandedPanel = ev.expand; } } diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/panel.component.html b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/panel.component.html index d39795e1..29455aee 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/panel.component.html +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/panel.component.html @@ -14,6 +14,11 @@ + + + + + diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/panel.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/panel.component.ts index 92a9f216..5ce6e7ac 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/panel.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/panel.component.ts @@ -8,7 +8,7 @@ import { ActivitiesPanelDirective } from '../../directives/template/openvidu-angular.directive'; import { PanelType } from '../../models/panel.model'; -import { PanelService } from '../../services/panel/panel.service'; +import { PanelEvent, PanelService } from '../../services/panel/panel.service'; /** * @@ -64,6 +64,11 @@ export class PanelComponent implements OnInit { */ @ContentChild('backgroundEffectsPanel', { read: TemplateRef }) backgroundEffectsPanelTemplate: TemplateRef; + /** + * @ignore + */ + @ContentChild('settingsPanel', { read: TemplateRef }) settingsPanelTemplate: TemplateRef; + /** * @ignore */ @@ -91,11 +96,22 @@ export class PanelComponent implements OnInit { set externalBackgroundEffectsPanel(externalBackgroundEffectsPanel: BackgroundEffectsPanelDirective) { // This directive will has value only when BACKGROUND EFFECTS PANEL component tagged with '*ovBackgroundEffectsPanel' // is inside of the PANEL component tagged with '*ovPanel' - if (externalBackgroundEffectsPanel) { - this.backgroundEffectsPanelTemplate = externalBackgroundEffectsPanel.template; - } + // TODO: backgroundEffectsPanel does not provides customization + // if (externalBackgroundEffectsPanel) { + // this.backgroundEffectsPanelTemplate = externalBackgroundEffectsPanel.template; + // } } + // TODO: settingsPanel does not provides customization + // @ContentChild(SettingsPanelDirective) + // set externalSettingsPanel(externalSettingsPanel: SettingsPanelDirective) { + // This directive will has value only when SETTINGS PANEL component tagged with '*ovSettingsPanel' + // is inside of the PANEL component tagged with '*ovPanel' + // if (externalSettingsPanel) { + // this.settingsPanelTemplate = externalSettingsPanel.template; + // } + // } + @ContentChild(ActivitiesPanelDirective) set externalActivitiesPanel(externalActivitiesPanel: ActivitiesPanelDirective) { // This directive will has value only when ACTIVITIES PANEL component tagged with '*ovActivitiesPanel' @@ -126,6 +142,7 @@ export class PanelComponent implements OnInit { isParticipantsPanelOpened: boolean; isChatPanelOpened: boolean; isBackgroundEffectsPanelOpened: boolean; + isSettingsPanelOpened: boolean; isActivitiesPanelOpened: boolean; /** @@ -150,15 +167,14 @@ export class PanelComponent implements OnInit { } private subscribeToPanelToggling() { - this.panelSubscription = this.panelService.panelOpenedObs - .pipe(skip(1)) - .subscribe((ev: { opened: boolean; type?: PanelType | string }) => { - this.isChatPanelOpened = ev.opened && ev.type === PanelType.CHAT; - this.isParticipantsPanelOpened = ev.opened && ev.type === PanelType.PARTICIPANTS; - this.isBackgroundEffectsPanelOpened = ev.opened && ev.type === PanelType.BACKGROUND_EFFECTS; - this.isActivitiesPanelOpened = ev.opened && ev.type === PanelType.ACTIVITIES; - this.isExternalPanelOpened = ev.opened && ev.type !== PanelType.PARTICIPANTS && ev.type !== PanelType.CHAT; - this.cd.markForCheck(); - }); + this.panelSubscription = this.panelService.panelOpenedObs.pipe(skip(1)).subscribe((ev: PanelEvent) => { + this.isChatPanelOpened = ev.opened && ev.type === PanelType.CHAT; + this.isParticipantsPanelOpened = ev.opened && ev.type === PanelType.PARTICIPANTS; + this.isBackgroundEffectsPanelOpened = ev.opened && ev.type === PanelType.BACKGROUND_EFFECTS; + this.isSettingsPanelOpened = ev.opened && ev.type === PanelType.SETTINGS; + this.isActivitiesPanelOpened = ev.opened && ev.type === PanelType.ACTIVITIES; + this.isExternalPanelOpened = ev.opened && ev.type !== PanelType.PARTICIPANTS && ev.type !== PanelType.CHAT; + this.cd.markForCheck(); + }); } } diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.css b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.css new file mode 100644 index 00000000..a19bd9fd --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.css @@ -0,0 +1,29 @@ +.settings-container { + display: flex; + padding: 10px; +} + +.item-menu { + padding-right: 5px; + border-right: 1px solid var(--ov-secondary-color); + width: 200px; +} + +.item-content { + padding: 16px; + flex-grow: 1; +} + +.option { + border-radius: var(--ov-panel-radius); +} +.lang-container button { + width: 100%; +} + +mat-list-option[aria-selected='true'] { + background: var(--ov-light-color); +} +::ng-deep .mat-list-item-content { + padding: 5px !important; +} diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.html b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.html new file mode 100644 index 00000000..92d824bc --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.html @@ -0,0 +1,43 @@ +
+
+

{{ 'PANEL.SETTINGS.TITLE' | translate }}

+ +
+ +
+
+ + + manage_accounts +
{{ 'PANEL.SETTINGS.GENERAL' | translate }}
+
+ + videocam +
{{ 'PANEL.SETTINGS.VIDEO' | translate }}
+
+ + mic +
{{ 'PANEL.SETTINGS.AUDIO' | translate }}
+
+
+
+ +
+
+ + + + + language +
{{ 'PANEL.SETTINGS.LANGUAGE' | translate }}:
+ +
+
+
+ + +
+
+
diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.spec.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.spec.ts new file mode 100644 index 00000000..e4ecf48e --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SettingsPanelComponent } from './settings-panel.component'; + +describe('SettingsPanelComponent', () => { + let component: SettingsPanelComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ SettingsPanelComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(SettingsPanelComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.ts new file mode 100644 index 00000000..facdd989 --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/panel/settings-panel/settings-panel.component.ts @@ -0,0 +1,20 @@ +import { Component, HostListener, OnInit } from '@angular/core'; +import { MatOptionSelectionChange } from '@angular/material/core'; +import { PanelType } from '../../../models/panel.model'; +import { PanelService } from '../../../services/panel/panel.service'; + +@Component({ + selector: 'ov-settings-panel', + templateUrl: './settings-panel.component.html', + styleUrls: ['../panel.component.css', './settings-panel.component.css'] +}) +export class SettingsPanelComponent implements OnInit { + + selectedOption: string; + constructor(private panelService: PanelService) {} + ngOnInit() {} + + close() { + this.panelService.togglePanel(PanelType.SETTINGS); + } +} diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/pre-join/pre-join.component.css b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/pre-join/pre-join.component.css index fd3e84c7..140e23a6 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/pre-join/pre-join.component.css +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/pre-join/pre-join.component.css @@ -11,11 +11,6 @@ flex: 1 1 auto; } -.lang-button { - background-color: var(--ov-logo-background-color); - color: var(--ov-text-color); -} - #branding-logo { background-color: var(--ov-logo-background-color); border-radius: var(--ov-panel-radius); @@ -81,31 +76,6 @@ hr { margin-bottom: 0px !important; } -#nickname-input-container, -.device-container-element { - display: flex; -} - -#nickname-input-container button, -.device-container-element button { - margin: auto 10px auto auto; -} - -#nickname-input-container button.mat-button-disabled { - color: #000000 !important; -} - -#nickname-input-container mat-form-field, -.device-container-element mat-form-field { - width: 100%; - margin-top: 10px; - color: #000000; -} - -#nickname-input-container mat-form-field { - color: #000000; -} - .mat-form-field-appearance-fill .mat-form-field-flex { /* background-color: var(--ov-text-color); */ border-radius: var(--ov-video-radius); @@ -118,11 +88,6 @@ hr { display: block !important; } -#camera-button { - border-radius: var(--ov-buttons-radius); - /* background-color: var(--ov-secondary-color) !important; */ - /* color: var(--ov-text-color) !important; */ -} .join-btn-container { width: inherit; @@ -137,37 +102,6 @@ hr { border-radius: var(--ov-video-radius); } -.warn-btn { - color: var(--ov-text-color); - background-color: var(--ov-warn-color) !important; -} - -.active-btn { - color: var(--ov-text-color); - background-color: var(--ov-tertiary-color) !important; -} -.media-btn { - margin: auto; -} - -::ng-deep .mat-button-toggle-appearance-standard .mat-button-toggle-label-content { - padding: 1px !important; -} - -::ng-deep .mat-input-element { - caret-color: #000000; -} -::ng-deep .mat-primary .mat-option.mat-selected:not(.mat-option-disabled) { - color: #000000; -} - -::ng-deep .mat-form-field-label { - color: var(--ov-panel-text-color) !important; -} - -::ng-deep .mat-form-field.mat-focused .mat-form-field-ripple { - background-color: var(--ov-panel-text-color) !important; -} @media only screen and (max-width: 480px) { .container, diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/pre-join/pre-join.component.html b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/pre-join/pre-join.component.html index 6b7e1569..5557efe9 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/pre-join/pre-join.component.html +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/pre-join/pre-join.component.html @@ -3,15 +3,8 @@ - - - - + +
@@ -50,98 +43,19 @@

{{ 'PREJOIN.NICKNAME_SECTION' | translate }}


-
- - - {{ 'PREJOIN.NICKNAME' | translate }} - - -
- +

{{ 'PREJOIN.DEVICE_SECTION' | translate }}


+ -
- - - {{ 'PREJOIN.VIDEO_DEVICE' | translate }} - - - {{ camera.label }} - - - -
+ -
- - - {{ 'PREJOIN.AUDIO_DEVICE' | translate }} - - - {{ microphone.label }} - - - -
+ +
diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/pre-join/pre-join.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/pre-join/pre-join.component.ts index 55393f4a..8be21045 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/pre-join/pre-join.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/pre-join/pre-join.component.ts @@ -2,7 +2,6 @@ import { Component, HostListener, OnDestroy, OnInit, Output, EventEmitter, ViewC import { MatMenuTrigger } from '@angular/material/menu'; import { MatSelect } from '@angular/material/select'; -import { PublisherProperties } from 'openvidu-browser'; import { Subscription } from 'rxjs'; import { CustomDevice } from '../../models/device.model'; import { ILogger } from '../../models/logger.model'; @@ -10,15 +9,10 @@ import { PanelType } from '../../models/panel.model'; import { ParticipantAbstractModel } from '../../models/participant.model'; import { CdkOverlayService } from '../../services/cdk-overlay/cdk-overlay.service'; import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service'; -import { DeviceService } from '../../services/device/device.service'; import { LayoutService } from '../../services/layout/layout.service'; import { LoggerService } from '../../services/logger/logger.service'; -import { OpenViduService } from '../../services/openvidu/openvidu.service'; import { PanelService } from '../../services/panel/panel.service'; import { ParticipantService } from '../../services/participant/participant.service'; -import { StorageService } from '../../services/storage/storage.service'; -import { TranslateService } from '../../services/translate/translate.service'; -import { VirtualBackgroundService } from '../../services/virtual-background/virtual-background.service'; /** * @internal @@ -39,8 +33,6 @@ export class PreJoinComponent implements OnInit, OnDestroy, AfterViewInit { @ViewChild(MatSelect) matSelect: MatSelect; @Output() onJoinButtonClicked = new EventEmitter(); - languages: { name: string; ISO: string }[] = []; - langSelected: { name: string; ISO: string }; cameras: CustomDevice[]; microphones: CustomDevice[]; cameraSelected: CustomDevice; @@ -79,15 +71,10 @@ export class PreJoinComponent implements OnInit, OnDestroy, AfterViewInit { constructor( private layoutService: LayoutService, - private deviceSrv: DeviceService, private loggerSrv: LoggerService, - private openviduService: OpenViduService, private participantService: ParticipantService, protected panelService: PanelService, private libService: OpenViduAngularConfigService, - private storageSrv: StorageService, - private backgroundService: VirtualBackgroundService, - private translateService: TranslateService, protected cdkSrv: CdkOverlayService ) { this.log = this.loggerSrv.get('PreJoinComponent'); @@ -96,20 +83,8 @@ export class PreJoinComponent implements OnInit, OnDestroy, AfterViewInit { ngOnInit() { this.subscribeToPrejoinDirectives(); this.subscribeToLocalParticipantEvents(); - this.languages = this.translateService.getLanguagesInfo(); - this.langSelected = this.translateService.getLangSelected(); this.windowSize = window.innerWidth; - this.hasVideoDevices = this.deviceSrv.hasVideoDeviceAvailable(); - this.hasAudioDevices = this.deviceSrv.hasAudioDeviceAvailable(); - this.microphones = this.deviceSrv.getMicrophones(); - this.cameras = this.deviceSrv.getCameras(); - this.cameraSelected = this.deviceSrv.getCameraSelected(); - this.microphoneSelected = this.deviceSrv.getMicrophoneSelected(); - - this.isVideoMuted = this.deviceSrv.isVideoMuted(); - this.isAudioMuted = this.deviceSrv.isAudioMuted(); - this.isLoading = false; } @@ -133,79 +108,6 @@ export class PreJoinComponent implements OnInit, OnDestroy, AfterViewInit { this.panelService.closePanel(); } - async onCameraSelected(event: any) { - const videoSource = event?.value; - // Is New deviceId different from the old one? - if (this.deviceSrv.needUpdateVideoTrack(videoSource)) { - const mirror = this.deviceSrv.cameraNeedsMirror(videoSource); - //TODO: Uncomment this when replaceTrack issue is fixed - // const pp: PublisherProperties = { videoSource, audioSource: false, mirror }; - // await this.openviduService.replaceTrack(VideoType.CAMERA, pp); - // TODO: Remove this when replaceTrack issue is fixed - const pp: PublisherProperties = { videoSource, audioSource: this.microphoneSelected.device, mirror }; - - // Reapply Virtual Background to new Publisher if necessary - const backgroundSelected = this.backgroundService.backgroundSelected.getValue(); - if (this.backgroundService.isBackgroundApplied()) { - await this.backgroundService.removeBackground(); - } - await this.openviduService.republishTrack(pp); - if (this.backgroundService.isBackgroundApplied()) { - await this.backgroundService.applyBackground(this.backgroundService.backgrounds.find((b) => b.id === backgroundSelected)); - } - - this.deviceSrv.setCameraSelected(videoSource); - this.cameraSelected = this.deviceSrv.getCameraSelected(); - } - } - - async onMicrophoneSelected(event: any) { - const audioSource = event?.value; - if (this.deviceSrv.needUpdateAudioTrack(audioSource)) { - //TODO: Uncomment this when replaceTrack issue is fixed - // const pp: PublisherProperties = { audioSource, videoSource: false }; - // await this.openviduService.replaceTrack(VideoType.CAMERA, pp); - // TODO: Remove this when replaceTrack issue is fixed - const mirror = this.deviceSrv.cameraNeedsMirror(this.cameraSelected.device); - const pp: PublisherProperties = { videoSource: this.cameraSelected.device, audioSource, mirror }; - await this.openviduService.republishTrack(pp); - - this.deviceSrv.setMicSelected(audioSource); - this.microphoneSelected = this.deviceSrv.getMicrophoneSelected(); - } - } - - onLangSelected(lang: string) { - this.translateService.setLanguage(lang); - this.storageSrv.setLang(lang); - this.langSelected = this.translateService.getLangSelected(); - } - - async toggleCam() { - this.videoMuteChanging = true; - const publish = this.isVideoMuted; - await this.openviduService.publishVideo(publish); - this.isVideoMuted = !this.isVideoMuted; - this.storageSrv.setVideoMuted(this.isVideoMuted); - if (this.isVideoMuted && this.panelService.isExternalPanelOpened()) { - this.panelService.togglePanel(PanelType.BACKGROUND_EFFECTS); - } - this.videoMuteChanging = false; - } - - toggleMic() { - const publish = this.isAudioMuted; - this.openviduService.publishAudio(publish); - this.isAudioMuted = !this.isAudioMuted; - this.storageSrv.setAudioMuted(this.isAudioMuted); - } - - updateNickname() { - this.nickname = this.nickname === '' ? this.participantService.getMyNickname() : this.nickname; - this.participantService.setMyNickname(this.nickname); - this.storageSrv.setNickname(this.nickname); - } - joinSession() { this.onJoinButtonClicked.emit(); this.panelService.closePanel(); diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/session/session.component.css b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/session/session.component.css index 4537917d..042cb4db 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/session/session.component.css +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/session/session.component.css @@ -24,6 +24,11 @@ z-index: 1; } +.big { + width: 650px; + max-width: 100%; +} + .mat-drawer.mat-drawer-side { z-index: 0 !important; } @@ -44,7 +49,8 @@ background-color: var(--ov-primary-color); } -#toolbar-container, #footer-container { +#toolbar-container, +#footer-container { background-color: var(--ov-primary-color); min-width: 400px !important; width: 100%; @@ -63,9 +69,7 @@ min-width: 400px !important; } - - -.reconnecting-container{ +.reconnecting-container { width: 100%; height: 100%; z-index: 1000; @@ -74,10 +78,28 @@ position: absolute; } - @media only screen and (max-width: 600px) { #session-container { width: 100%; /* position: fixed; */ } } + +::ng-deep .mat-button-toggle-appearance-standard .mat-button-toggle-label-content { + padding: 1px !important; +} + +::ng-deep .mat-input-element { + caret-color: #000000; +} +::ng-deep .mat-primary .mat-option.mat-selected:not(.mat-option-disabled) { + color: #000000; +} + +::ng-deep .mat-form-field-label { + color: var(--ov-panel-text-color) !important; +} + +::ng-deep .mat-form-field.mat-focused .mat-form-field-ripple { + background-color: var(--ov-panel-text-color) !important; +} \ No newline at end of file diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/session/session.component.html b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/session/session.component.html index 7e2fc943..6a9bb0f8 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/session/session.component.html +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/session/session.component.html @@ -1,10 +1,11 @@
- + { + if (container) { + this.drawer = container; + this.drawer._contentMarginChanges.subscribe(() => { + setTimeout(() => { + this.stopUpdateLayoutInterval(); + this.layoutService.update(); + this.drawer.autosize = false; + }, 250); + }); + } + }, 0); + } + async ngOnInit() { if (!this.usedInPrejoinPage) { - if(!this.tokenService.getScreenToken()){ + if (!this.tokenService.getScreenToken()) { // Hide screenshare button if screen token does not exist this.libService.screenshareButton.next(false); } @@ -170,27 +191,34 @@ export class SessionComponent implements OnInit { protected subscribeToTogglingMenu() { this.sideMenu.openedChange.subscribe(() => { - if (this.updateLayoutInterval) { - clearInterval(this.updateLayoutInterval); - } + this.stopUpdateLayoutInterval(); this.layoutService.update(); }); this.sideMenu.openedStart.subscribe(() => { - this.updateLayoutInterval = setInterval(() => this.layoutService.update(), 50); + this.startUpdateLayoutInterval(); }); this.sideMenu.closedStart.subscribe(() => { - this.updateLayoutInterval = setInterval(() => this.layoutService.update(), 50); + this.startUpdateLayoutInterval(); }); - this.menuSubscription = this.panelService.panelOpenedObs - .pipe(skip(1)) - .subscribe((ev: { opened: boolean; type?: PanelType | string }) => { - if (this.sideMenu) { - ev.opened ? this.sideMenu.open() : this.sideMenu.close(); + this.menuSubscription = this.panelService.panelOpenedObs.pipe(skip(1)).subscribe((ev: PanelEvent) => { + if (this.sideMenu) { + this.settingsPanelOpened = ev.opened && ev.type === PanelType.SETTINGS; + + if (this.sideMenu.opened && ev.opened) { + if (ev.type === PanelType.SETTINGS || ev.oldType === PanelType.SETTINGS) { + // Switch from SETTINGS to another panel and vice versa. + // As the SETTINGS panel will be bigger than others, the sidenav container must be updated. + // Setting autosize to 'true' allows update it. + this.drawer.autosize = true; + this.startUpdateLayoutInterval(); + } } - }); + ev.opened ? this.sideMenu.open() : this.sideMenu.close(); + } + }); } protected subscribeToLayoutWidth() { @@ -324,4 +352,16 @@ export class SessionComponent implements OnInit { this.recordingService.stopRecording(event); }); } + + private startUpdateLayoutInterval() { + this.updateLayoutInterval = setInterval(() => { + this.layoutService.update(); + }, 50); + } + + private stopUpdateLayoutInterval() { + if (this.updateLayoutInterval) { + clearInterval(this.updateLayoutInterval); + } + } } diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/audio-devices/audio-devices.component.css b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/audio-devices/audio-devices.component.css new file mode 100644 index 00000000..595a9382 --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/audio-devices/audio-devices.component.css @@ -0,0 +1,17 @@ +.device-container-element mat-form-field { + width: 100%; + margin-top: 10px; + color: #000000; +} +.device-container-element button { + margin: auto 10px auto auto; +} + +.device-container-element { + display: flex; +} + +.warn-btn { + color: var(--ov-text-color); + background-color: var(--ov-warn-color) !important; +} diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/audio-devices/audio-devices.component.html b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/audio-devices/audio-devices.component.html new file mode 100644 index 00000000..c5522572 --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/audio-devices/audio-devices.component.html @@ -0,0 +1,26 @@ +
+ + + {{ 'PREJOIN.AUDIO_DEVICE' | translate }} + + + {{ microphone.label }} + + + +
diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/audio-devices/audio-devices.component.spec.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/audio-devices/audio-devices.component.spec.ts new file mode 100644 index 00000000..20d1d7fe --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/audio-devices/audio-devices.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AudioDevicesComponent } from './audio-devices.component'; + +describe('AudioDevicesComponent', () => { + let component: AudioDevicesComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ AudioDevicesComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(AudioDevicesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/audio-devices/audio-devices.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/audio-devices/audio-devices.component.ts new file mode 100644 index 00000000..ce6a3597 --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/audio-devices/audio-devices.component.ts @@ -0,0 +1,80 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { PublisherProperties } from 'openvidu-browser'; +import { DeviceService } from '../../../services/device/device.service'; +import { OpenViduService } from '../../../services/openvidu/openvidu.service'; +import { StorageService } from '../../../services/storage/storage.service'; +import { CustomDevice } from '../../../models/device.model'; +import { ParticipantAbstractModel } from '../../../models/participant.model'; +import { ParticipantService } from '../../../services/participant/participant.service'; +import { Subscription } from 'rxjs'; + +/** + * @internal + */ +@Component({ + selector: 'ov-audio-devices-select', + templateUrl: './audio-devices.component.html', + styleUrls: ['./audio-devices.component.css'] +}) +export class AudioDevicesComponent implements OnInit, OnDestroy { + hasAudioDevices: boolean; + isAudioMuted: boolean; + microphoneSelected: CustomDevice; + microphones: CustomDevice[] = []; + private localParticipantSubscription: Subscription; + + constructor( + private openviduService: OpenViduService, + private deviceSrv: DeviceService, + private storageSrv: StorageService, + protected participantService: ParticipantService + ) {} + + ngOnInit(): void { + this.subscribeToParticipantMediaProperties(); + + this.hasAudioDevices = this.deviceSrv.hasAudioDeviceAvailable(); + this.microphones = this.deviceSrv.getMicrophones(); + this.microphoneSelected = this.deviceSrv.getMicrophoneSelected(); + this.isAudioMuted = this.deviceSrv.isAudioMuted(); + if (this.openviduService.isSessionConnected()) { + this.isAudioMuted = !this.participantService.isMyAudioActive(); + } else { + this.isAudioMuted = this.deviceSrv.isAudioMuted(); + } + } + + ngOnDestroy() { + if (this.localParticipantSubscription) this.localParticipantSubscription.unsubscribe(); + } + + toggleMic() { + const publish = this.isAudioMuted; + this.openviduService.publishAudio(publish); + } + + async onMicrophoneSelected(event: any) { + const audioSource = event?.value; + if (this.deviceSrv.needUpdateAudioTrack(audioSource)) { + //TODO: Uncomment this when replaceTrack issue is fixed + // const pp: PublisherProperties = { audioSource, videoSource: false }; + // await this.openviduService.replaceTrack(VideoType.CAMERA, pp); + // TODO: Remove this when replaceTrack issue is fixed + const mirror = this.deviceSrv.cameraNeedsMirror(this.deviceSrv.getCameraSelected().device); + const pp: PublisherProperties = { videoSource: this.deviceSrv.getCameraSelected().device, audioSource, mirror }; + await this.openviduService.republishTrack(pp); + + this.deviceSrv.setMicSelected(audioSource); + this.microphoneSelected = this.deviceSrv.getMicrophoneSelected(); + } + } + + private subscribeToParticipantMediaProperties() { + this.localParticipantSubscription = this.participantService.localParticipantObs.subscribe((p: ParticipantAbstractModel) => { + if (p) { + this.isAudioMuted = !p.hasAudioActive(); + this.storageSrv.setAudioMuted(this.isAudioMuted); + } + }); + } +} diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/lang-selector/lang-selector.component.css b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/lang-selector/lang-selector.component.css new file mode 100644 index 00000000..492806a3 --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/lang-selector/lang-selector.component.css @@ -0,0 +1,4 @@ +.lang-button { + background-color: var(--ov-logo-background-color); + color: var(--ov-text-color); +} \ No newline at end of file diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/lang-selector/lang-selector.component.html b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/lang-selector/lang-selector.component.html new file mode 100644 index 00000000..6b020237 --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/lang-selector/lang-selector.component.html @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/lang-selector/lang-selector.component.spec.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/lang-selector/lang-selector.component.spec.ts new file mode 100644 index 00000000..c20c379c --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/lang-selector/lang-selector.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LangSelectorComponent } from './lang-selector.component'; + +describe('LangSelectorComponent', () => { + let component: LangSelectorComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ LangSelectorComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(LangSelectorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/lang-selector/lang-selector.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/lang-selector/lang-selector.component.ts new file mode 100644 index 00000000..9e0302d0 --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/lang-selector/lang-selector.component.ts @@ -0,0 +1,26 @@ +import { Component, OnInit } from '@angular/core'; +import { StorageService } from '../../../services/storage/storage.service'; +import { TranslateService } from '../../../services/translate/translate.service'; + +@Component({ + selector: 'ov-lang-selector', + templateUrl: './lang-selector.component.html', + styleUrls: ['./lang-selector.component.css'] +}) +export class LangSelectorComponent implements OnInit { + langSelected: { name: string; ISO: string }; + languages: { name: string; ISO: string }[] = []; + + constructor(private translateService: TranslateService, private storageSrv: StorageService) {} + + ngOnInit(): void { + this.languages = this.translateService.getLanguagesInfo(); + this.langSelected = this.translateService.getLangSelected(); + } + + onLangSelected(lang: string) { + this.translateService.setLanguage(lang); + this.storageSrv.setLang(lang); + this.langSelected = this.translateService.getLangSelected(); + } +} diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/nickname-input/nickname-input.component.css b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/nickname-input/nickname-input.component.css new file mode 100644 index 00000000..f4fd3262 --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/nickname-input/nickname-input.component.css @@ -0,0 +1,21 @@ +#nickname-input-container { + display: flex; +} + +#nickname-input-container button { + margin: auto 10px auto auto; +} + +#nickname-input-container button.mat-button-disabled { + color: #000000 !important; +} + +#nickname-input-container mat-form-field { + width: 100%; + margin-top: 10px; + color: #000000; +} + +#nickname-input-container mat-form-field { + color: #000000; +} \ No newline at end of file diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/nickname-input/nickname-input.component.html b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/nickname-input/nickname-input.component.html new file mode 100644 index 00000000..2c7d3478 --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/nickname-input/nickname-input.component.html @@ -0,0 +1,16 @@ +
+ + + {{ 'PREJOIN.NICKNAME' | translate }} + + +
\ No newline at end of file diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/nickname-input/nickname-input.component.spec.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/nickname-input/nickname-input.component.spec.ts new file mode 100644 index 00000000..7faded0c --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/nickname-input/nickname-input.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { NicknameInputComponent } from './nickname-input.component'; + +describe('NicknameInputComponent', () => { + let component: NicknameInputComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ NicknameInputComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(NicknameInputComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/nickname-input/nickname-input.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/nickname-input/nickname-input.component.ts new file mode 100644 index 00000000..d05017b4 --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/nickname-input/nickname-input.component.ts @@ -0,0 +1,36 @@ +import { Component, OnInit } from '@angular/core'; +import { Subscription } from 'rxjs'; +import { ParticipantAbstractModel } from '../../../models/participant.model'; +import { ParticipantService } from '../../../services/participant/participant.service'; +import { StorageService } from '../../../services/storage/storage.service'; + +@Component({ + selector: 'ov-nickname-input', + templateUrl: './nickname-input.component.html', + styleUrls: ['./nickname-input.component.css'] +}) +export class NicknameInputComponent implements OnInit { + nickname: string; + localParticipantSubscription: Subscription; + + constructor(private participantService: ParticipantService, private storageSrv: StorageService) {} + + ngOnInit(): void { + this.subscribeToParticipantProperties(); + this.nickname = this.participantService.getMyNickname(); + } + + updateNickname() { + this.nickname = this.nickname === '' ? this.participantService.getMyNickname() : this.nickname; + this.participantService.setMyNickname(this.nickname); + this.storageSrv.setNickname(this.nickname); + } + + private subscribeToParticipantProperties() { + this.localParticipantSubscription = this.participantService.localParticipantObs.subscribe((p: ParticipantAbstractModel) => { + if (p) { + this.nickname = p.getNickname(); + } + }); + } +} diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/video-devices/video-devices.component.css b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/video-devices/video-devices.component.css new file mode 100644 index 00000000..86427b3b --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/video-devices/video-devices.component.css @@ -0,0 +1,25 @@ +#camera-button { + border-radius: var(--ov-buttons-radius); + /* background-color: var(--ov-secondary-color) !important; */ + /* color: var(--ov-text-color) !important; */ +} + +.device-container-element mat-form-field { + width: 100%; + margin-top: 10px; + color: #000000; +} + +.device-container-element button { + margin: auto 10px auto auto; +} + +.device-container-element { + display: flex; +} + +.warn-btn { + color: var(--ov-text-color); + background-color: var(--ov-warn-color) !important; +} + diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/video-devices/video-devices.component.html b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/video-devices/video-devices.component.html new file mode 100644 index 00000000..ecb5b231 --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/video-devices/video-devices.component.html @@ -0,0 +1,24 @@ +
+ + + {{ 'PREJOIN.VIDEO_DEVICE' | translate }} + + + {{ camera.label }} + + + +
diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/video-devices/video-devices.component.spec.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/video-devices/video-devices.component.spec.ts new file mode 100644 index 00000000..2ceb1f81 --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/video-devices/video-devices.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { VideoDevicesComponent } from './video-devices.component'; + +describe('VideoDevicesComponent', () => { + let component: VideoDevicesComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ VideoDevicesComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(VideoDevicesComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/video-devices/video-devices.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/video-devices/video-devices.component.ts new file mode 100644 index 00000000..47038bbd --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/settings/video-devices/video-devices.component.ts @@ -0,0 +1,102 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { PublisherProperties } from 'openvidu-browser'; +import { Subscription } from 'rxjs'; +import { CustomDevice } from '../../../models/device.model'; +import { PanelType } from '../../../models/panel.model'; +import { ParticipantAbstractModel } from '../../../models/participant.model'; +import { DeviceService } from '../../../services/device/device.service'; +import { OpenViduService } from '../../../services/openvidu/openvidu.service'; +import { PanelService } from '../../../services/panel/panel.service'; +import { ParticipantService } from '../../../services/participant/participant.service'; +import { StorageService } from '../../../services/storage/storage.service'; +import { VirtualBackgroundService } from '../../../services/virtual-background/virtual-background.service'; + +/** + * @internal + */ +@Component({ + selector: 'ov-video-devices-select', + templateUrl: './video-devices.component.html', + styleUrls: ['./video-devices.component.css'] +}) +export class VideoDevicesComponent implements OnInit, OnDestroy { + videoMuteChanging: boolean; + isVideoMuted: boolean; + cameraSelected: CustomDevice; + hasVideoDevices: boolean; + cameras: CustomDevice[]; + localParticipantSubscription: Subscription; + + constructor( + private openviduService: OpenViduService, + protected panelService: PanelService, + private storageSrv: StorageService, + private deviceSrv: DeviceService, + protected participantService: ParticipantService, + private backgroundService: VirtualBackgroundService + ) {} + + ngOnInit(): void { + this.subscribeToParticipantMediaProperties(); + this.hasVideoDevices = this.deviceSrv.hasVideoDeviceAvailable(); + this.cameras = this.deviceSrv.getCameras(); + this.cameraSelected = this.deviceSrv.getCameraSelected(); + if (this.openviduService.isSessionConnected()) { + this.isVideoMuted = !this.participantService.getLocalParticipant().isCameraVideoActive(); + } else { + this.isVideoMuted = this.deviceSrv.isVideoMuted(); + } + } + async ngOnDestroy() { + this.cameras = []; + if (this.localParticipantSubscription) this.localParticipantSubscription.unsubscribe(); + } + + async toggleCam() { + this.videoMuteChanging = true; + const publish = this.isVideoMuted; + await this.openviduService.publishVideo(publish); + this.storageSrv.setVideoMuted(this.isVideoMuted); + if (this.isVideoMuted && this.panelService.isExternalPanelOpened()) { + this.panelService.togglePanel(PanelType.BACKGROUND_EFFECTS); + } + this.videoMuteChanging = false; + } + + async onCameraSelected(event: any) { + const videoSource = event?.value; + // Is New deviceId different from the old one? + if (this.deviceSrv.needUpdateVideoTrack(videoSource)) { + const mirror = this.deviceSrv.cameraNeedsMirror(videoSource); + //TODO: Uncomment this when replaceTrack issue is fixed + // const pp: PublisherProperties = { videoSource, audioSource: false, mirror }; + // await this.openviduService.replaceTrack(VideoType.CAMERA, pp); + // TODO: Remove this when replaceTrack issue is fixed + const pp: PublisherProperties = { videoSource, audioSource: this.deviceSrv.getMicrophoneSelected().device, mirror }; + + // Reapply Virtual Background to new Publisher if necessary + const backgroundSelected = this.backgroundService.backgroundSelected.getValue(); + if (this.backgroundService.isBackgroundApplied()) { + await this.backgroundService.removeBackground(); + } + await this.openviduService.republishTrack(pp); + if (this.backgroundService.isBackgroundApplied()) { + const bgSelected = this.backgroundService.backgrounds.find((b) => b.id === backgroundSelected); + if (bgSelected) { + await this.backgroundService.applyBackground(bgSelected); + } + } + + this.deviceSrv.setCameraSelected(videoSource); + this.cameraSelected = this.deviceSrv.getCameraSelected(); + } + } + + protected subscribeToParticipantMediaProperties() { + this.localParticipantSubscription = this.participantService.localParticipantObs.subscribe((p: ParticipantAbstractModel) => { + if (p) { + this.isVideoMuted = !p.isCameraVideoActive(); + } + }); + } +} diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/stream/stream.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/stream/stream.component.ts index 37e7f7ad..75a15648 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/stream/stream.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/stream/stream.component.ts @@ -212,7 +212,7 @@ export class StreamComponent implements OnInit { * @ignore */ toggleNicknameForm() { - if (this._stream.participant.local) { + if (this._stream?.participant?.local) { this.toggleNickname = !this.toggleNickname; } } @@ -260,7 +260,7 @@ export class StreamComponent implements OnInit { this.showAudioDetection = value; // this.cd.markForCheck(); }); - this.settingsButtonSub = this.libService.settingsButtonObs.subscribe((value: boolean) => { + this.settingsButtonSub = this.libService.streamSettingsButtonObs.subscribe((value: boolean) => { this.showSettingsButton = value; // this.cd.markForCheck(); }); diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.css b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.css index 80178013..0ca21a33 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.css +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.css @@ -83,8 +83,8 @@ .recording-tag mat-icon { font-size: 16px; display: inline; - vertical-align: sub; - margin-right: 5px; + vertical-align: sub; + margin-right: 5px; } .blink { @@ -124,6 +124,15 @@ .mat-icon-button[disabled] { color: #fff; } +.divider { + margin: 8px 0px; +} +::ng-deep .mat-menu-item { + /* margin-bottom: 10px; */ + height: 40px; + line-height: 40px; +} + @media (max-width: 750px) { #session-name { display: none; @@ -143,10 +152,8 @@ } } -::ng-deep .mat-menu-panel { - margin-bottom: 10px; -} - @keyframes blinker { - 50% { opacity: 0.3; } -} \ No newline at end of file + 50% { + opacity: 0.3; + } +} diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.html b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.html index e9179089..d3bda33a 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.html +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.html @@ -102,6 +102,14 @@ auto_awesome {{ 'TOOLBAR.BACKGROUND' | translate }} + + + + + diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.ts index 652e309d..821ed819 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/toolbar/toolbar.component.ts @@ -15,7 +15,7 @@ import { import { first, skip, Subscription } from 'rxjs'; import { TokenService } from '../../services/token/token.service'; import { ChatService } from '../../services/chat/chat.service'; -import { PanelService } from '../../services/panel/panel.service'; +import { PanelEvent, PanelService } from '../../services/panel/panel.service'; import { DocumentService } from '../../services/document/document.service'; import { OpenViduService } from '../../services/openvidu/openvidu.service'; @@ -272,6 +272,11 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit { */ showRecordingButton: boolean = true; + /** + * @ignore + */ + showSettingsButton: boolean = true; + /** * @ignore */ @@ -344,6 +349,7 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit { private displayLogoSub: Subscription; private displaySessionNameSub: Subscription; private screenSizeSub: Subscription; + private settingsButtonSub: Subscription; private currentWindowHeight = window.innerHeight; /** @@ -432,6 +438,7 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit { if (this.activitiesPanelButtonSub) this.activitiesPanelButtonSub.unsubscribe(); if (this.recordingSubscription) this.recordingSubscription.unsubscribe(); if (this.screenSizeSub) this.screenSizeSub.unsubscribe(); + if (this.settingsButtonSub) this.settingsButtonSub.unsubscribe(); } /** @@ -522,6 +529,13 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit { this.panelService.togglePanel(PanelType.BACKGROUND_EFFECTS); } + /** + * @ignore + */ + toggleSettings() { + this.panelService.togglePanel(PanelType.SETTINGS); + } + /** * @ignore */ @@ -564,17 +578,15 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit { }); } protected subscribeToMenuToggling() { - this.panelTogglingSubscription = this.panelService.panelOpenedObs.subscribe( - (ev: { opened: boolean; type?: PanelType | string }) => { - this.isChatOpened = ev.opened && ev.type === PanelType.CHAT; - this.isParticipantsOpened = ev.opened && ev.type === PanelType.PARTICIPANTS; - this.isActivitiesOpened = ev.opened && ev.type === PanelType.ACTIVITIES; - if (this.isChatOpened) { - this.unreadMessages = 0; - } - this.cd.markForCheck(); + this.panelTogglingSubscription = this.panelService.panelOpenedObs.subscribe((ev: PanelEvent) => { + this.isChatOpened = ev.opened && ev.type === PanelType.CHAT; + this.isParticipantsOpened = ev.opened && ev.type === PanelType.PARTICIPANTS; + this.isActivitiesOpened = ev.opened && ev.type === PanelType.ACTIVITIES; + if (this.isChatOpened) { + this.unreadMessages = 0; } - ); + this.cd.markForCheck(); + }); } protected subscribeToChatMessages() { @@ -590,7 +602,7 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit { this.localParticipantSubscription = this.participantService.localParticipantObs.subscribe((p: ParticipantAbstractModel) => { if (p) { this.isWebcamVideoActive = p.isCameraVideoActive(); - this.isAudioActive = p.isCameraAudioActive() || p.isScreenAudioActive(); + this.isAudioActive = p.hasAudioActive(); this.isScreenShareActive = p.isScreenActive(); this.isSessionCreator = p.getRole() === OpenViduRole.MODERATOR; this.cd.markForCheck(); @@ -627,11 +639,17 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit { this.cd.markForCheck(); }); - this.recordingButtonSub = this.libService.recordingButton.subscribe((value: boolean) => { + this.recordingButtonSub = this.libService.recordingButtonObs.subscribe((value: boolean) => { this.showRecordingButton = value; this.checkDisplayMoreOptions(); this.cd.markForCheck(); }); + + this.settingsButtonSub = this.libService.toolbarSettingsButtonObs.subscribe((value: boolean) => { + this.showSettingsButton = value; + this.checkDisplayMoreOptions(); + this.cd.markForCheck(); + }); this.chatPanelButtonSub = this.libService.chatPanelButtonObs.subscribe((value: boolean) => { this.showChatPanelButton = value; this.cd.markForCheck(); @@ -661,12 +679,12 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit { private subscribeToScreenSize() { this.screenSizeSub = this.documentService.screenSizeObs.subscribe((change: MediaChange[]) => { - console.log(change[0].mqAlias) this.screenSize = change[0].mqAlias; }); } private checkDisplayMoreOptions() { - this.showMoreOptionsButton = this.showFullscreenButton || this.showBackgroundEffectsButton || this.showRecordingButton; + this.showMoreOptionsButton = + this.showFullscreenButton || this.showBackgroundEffectsButton || this.showRecordingButton || this.showSettingsButton; } } diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.html b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.html index 85749765..ac863c81 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.html +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.html @@ -75,6 +75,10 @@ + + + + diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.ts index 3fb50f65..89bf3913 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/components/videoconference/videoconference.component.ts @@ -688,7 +688,7 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni // The devices are initialized without labels in Firefox. // We need to force an update after publisher is allowed. if (this.deviceSrv.areEmptyLabels()) { - await this.deviceSrv.forceUpdate(); + await this.deviceSrv.initializeDevices(); if (this.deviceSrv.hasAudioDeviceAvailable()) { const audioLabel = this.participantService.getMyCameraPublisher()?.stream?.getMediaStream()?.getAudioTracks()[0]?.label; this.deviceSrv.setMicSelected(audioLabel); diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/api.directive.module.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/api.directive.module.ts index a4a3a0c9..95e96c15 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/api.directive.module.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/api.directive.module.ts @@ -19,7 +19,8 @@ import { ToolbarDisplayLogoDirective, ToolbarActivitiesPanelButtonDirective, ToolbarBackgroundEffectsButtonDirective, - ToolbarRecordingButtonDirective + ToolbarRecordingButtonDirective, + ToolbarSettingsButtonDirective } from './toolbar.directive'; import { AudioMutedDirective, @@ -47,6 +48,7 @@ import { ToolbarActivitiesPanelButtonDirective, ToolbarDisplaySessionNameDirective, ToolbarDisplayLogoDirective, + ToolbarSettingsButtonDirective, StreamDisplayParticipantNameDirective, StreamDisplayAudioDetectionDirective, StreamSettingsButtonDirective, @@ -75,6 +77,7 @@ import { ToolbarActivitiesPanelButtonDirective, ToolbarDisplaySessionNameDirective, ToolbarDisplayLogoDirective, + ToolbarSettingsButtonDirective, StreamDisplayParticipantNameDirective, StreamDisplayAudioDetectionDirective, StreamSettingsButtonDirective, diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/stream.directive.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/stream.directive.ts index eadf7f77..afecdf7a 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/stream.directive.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/stream.directive.ts @@ -142,8 +142,8 @@ export class StreamSettingsButtonDirective implements AfterViewInit, OnDestroy { } update(value: boolean) { - if (this.libService.settingsButton.getValue() !== value) { - this.libService.settingsButton.next(value); + if (this.libService.streamSettingsButton.getValue() !== value) { + this.libService.streamSettingsButton.next(value); } } diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/toolbar.directive.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/toolbar.directive.ts index 7b81487c..e15c4a8e 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/toolbar.directive.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/api/toolbar.directive.ts @@ -242,6 +242,65 @@ export class ToolbarBackgroundEffectsButtonDirective implements AfterViewInit, O } } +/** + * The **settingsButton** directive allows show/hide the settings toolbar button. + * + * Default: `true` + * + * It can be used in the parent element {@link VideoconferenceComponent} specifying the name of the `toolbar` component: + * + * @example + * + * + * \ + * And it also can be used in the {@link ToolbarComponent}. + * @example + * + */ + @Directive({ + selector: 'ov-videoconference[toolbarSettingsButton], ov-toolbar[settingsButton]' +}) +export class ToolbarSettingsButtonDirective implements AfterViewInit, OnDestroy { + /** + * @ignore + */ + @Input() set toolbarSettingsButton(value: boolean) { + this.settingsValue = value; + this.update(this.settingsValue); + } + /** + * @ignore + */ + @Input() set settingsButton(value: boolean) { + this.settingsValue = value; + this.update(this.settingsValue); + } + + private settingsValue: boolean = true; + + /** + * @ignore + */ + constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {} + + ngAfterViewInit() { + this.update(this.settingsValue); + } + ngOnDestroy(): void { + this.clear(); + } + private clear() { + this.settingsValue = true; + this.update(true); + } + + private update(value: boolean) { + if (this.libService.toolbarSettingsButton.getValue() !== value) { + this.libService.toolbarSettingsButton.next(value); + } + } +} + /** * The **leaveButton** directive allows show/hide the leave toolbar button. * diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/template/openvidu-angular.directive.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/template/openvidu-angular.directive.ts index 3528aa55..51b4c4de 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/template/openvidu-angular.directive.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/directives/template/openvidu-angular.directive.ts @@ -259,7 +259,7 @@ export class PanelDirective { * this.subscribeToPanelToggling(); * } * subscribeToPanelToggling() { - * this.panelService.panelOpenedObs.subscribe((ev: { opened: boolean; type?: PanelType | string }) => { + * this.panelService.panelOpenedObs.subscribe((ev: PanelEvent) => { * this.showExternalPanel = ev.opened && ev.type === 'my-panel'; * this.showExternalPanel2 = ev.opened && ev.type === 'my-panel2'; * }); diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/cn.json b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/cn.json index a556961f..9f507d2a 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/cn.json +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/cn.json @@ -37,6 +37,7 @@ "BACKGROUND":"背景效果", "START_RECORDING": "开始录音", "STOP_RECORDING": "停止录制", + "SETTINGS":"设置", "LEAVE":"离开会议", "PARTICIPANTS":"参与者", "CHAT":"聊天", @@ -64,6 +65,13 @@ "CAMERA": "摄像头", "SCREEN": "屏幕" }, + "SETTINGS": { + "TITLE": "设置", + "GENERAL": "一般的", + "VIDEO": "视频", + "AUDIO": "声音的", + "LANGUAGE": "语" + }, "BACKGROUND": { "TITLE": "背景效果", "BLURRED_SECTION": "没有效果和模糊的背景", diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/de.json b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/de.json index 2524015b..4cb81d9d 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/de.json +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/de.json @@ -37,6 +37,7 @@ "BACKGROUND": "Hintergrund-Effekte", "START_RECORDING": "Aufzeichnung starten", "STOP_RECORDING": "Aufzeichnung stoppen", + "SETTINGS": "Einstellungen", "LEAVE": "Die Sitzung verlassen", "PARTICIPANTS": "Teilnehmer", "CHAT": "Chat", @@ -64,6 +65,13 @@ "CAMERA": "KAMERA", "SCREEN": "BILDSCHIRM" }, + "SETTINGS": { + "TITLE": "Einstellungen", + "GENERAL": "Allgemein", + "VIDEO": "Video", + "AUDIO": "Audio", + "LANGUAGE": "Sprache" + }, "BACKGROUND": { "TITLE": "Hintergrund-Effekte", "BLURRED_SECTION": "Keine Effekte und unscharfer Hintergrund", @@ -98,4 +106,4 @@ "MEDIA_ACCESS": "Der Zugriff auf Mediengeräte war nicht erlaubt.", "DEVICE_NOT_FOUND": "Es wurden keine Video- oder Audiogeräte gefunden. Bitte schließen Sie mindestens eines an." } -} \ No newline at end of file +} diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/en.json b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/en.json index ff6e4e71..f98947c4 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/en.json +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/en.json @@ -38,6 +38,7 @@ "BACKGROUND": "Background effects", "START_RECORDING": "Start recording", "STOP_RECORDING": "Stop recording", + "SETTINGS": "Settings", "LEAVE": "Leave the session", "PARTICIPANTS": "Participants", "CHAT": "Chat", @@ -65,6 +66,13 @@ "CAMERA": "CAMERA", "SCREEN": "SCREEN" }, + "SETTINGS": { + "TITLE": "Settings", + "GENERAL": "General", + "VIDEO": "Video", + "AUDIO": "Audio", + "LANGUAGE": "Language" + }, "BACKGROUND": { "TITLE": "Background effects", "BLURRED_SECTION": "No effects and blurred background", diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/es.json b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/es.json index 374bd534..83de70b0 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/es.json +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/es.json @@ -37,6 +37,7 @@ "BACKGROUND": "Efectos de fondo", "START_RECORDING": "Iniciar grabación", "STOP_RECORDING": "Detener grabación", + "SETTINGS": "Configuración", "LEAVE": "Salir de la sesión", "PARTICIPANTS": "Participantes", "CHAT": "Chat", @@ -64,6 +65,13 @@ "CAMERA": "CÁMARA", "SCREEN": "PANTALLA" }, + "SETTINGS": { + "TITLE": "Configuración", + "GENERAL": "General", + "VIDEO": "Video", + "AUDIO": "Audio", + "LANGUAGE": "Idioma" + }, "BACKGROUND": { "TITLE": "Efectos de fondo", "BLURRED_SECTION": "Sin efectos y fondo desenfocado", diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/fr.json b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/fr.json index 0dc84c7b..526acd94 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/fr.json +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/fr.json @@ -37,6 +37,7 @@ "BACKGROUND": "Effets de fond", "START_RECORDING": "démarrer l'enregistrement", "STOP_RECORDING": "Arrêter l'enregistrement", + "SETTINGS": "Paramètres", "LEAVE": "Quitter la session", "PARTICIPANTS": "Participants", "CHAT": "Chat", @@ -64,6 +65,13 @@ "CAMERA": "CAMÉRA", "SCREEN": "ÉCRAN" }, + "SETTINGS": { + "TITLE": "Paramètres", + "GENERAL": "Général", + "VIDEO": "Vidéo", + "AUDIO": "l'audio", + "LANGUAGE": "Langue" + }, "BACKGROUND": { "TITLE": "Effets de fond", "BLURRED_SECTION": "Aucun effet et arrière-plan flou", diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/hi.json b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/hi.json index ccdc74b2..2a03a3fe 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/hi.json +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/hi.json @@ -37,6 +37,7 @@ "BACKGROUND": "पृष्ठभूमि प्रभाव", "START_RECORDING": "रिकॉर्डिंग प्रारंभ करें", "STOP_RECORDING": "रिकॉर्डिंग रोकें", + "SETTINGS": "सेटिंग्स", "LEAVE": "सत्र छोड़ें", "PARTICIPANTS": "सदस्य", "CHAT": "बातचीत", @@ -64,6 +65,13 @@ "CAMERA": "कैमरा", "SCREEN": "स्क्रीन" }, + "SETTINGS": { + "TITLE": "सेटिंग्स", + "GENERAL": "सामान्य", + "VIDEO": "वीडियो", + "AUDIO": "ऑडियो", + "LANGUAGE": "भाषा" + }, "BACKGROUND": { "TITLE": "पृष्ठभूमि प्रभाव", "BLURRED_SECTION": "कोई प्रभाव नहीं है और पृष्ठभूमि धुंधली है", diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/it.json b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/it.json index 367aeeb6..3704d216 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/it.json +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/it.json @@ -37,6 +37,7 @@ "BACKGROUND": "Effetti di sfondo", "START_RECORDING": "Avvia registrazione", "STOP_RECORDING": "Interrompi registrazione", + "SETTINGS": "Impostazioni", "LEAVE": "Abbandona la sessione", "PARTICIPANTS": "Partecipanti", "CHAT": "Chat", @@ -64,6 +65,13 @@ "CAMERA": "CAMERA", "SCREEN": "SCREEN" }, + "SETTINGS": { + "TITLE": "Impostazioni", + "GENERAL": "Generale", + "VIDEO": "video", + "AUDIO": "Audio", + "LANGUAGE":"Lingua" + }, "BACKGROUND": { "TITLE": "Effetti di sfondo", "BLURRED_SECTION": "Nessun effetto e sfondo sfocato", diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/ja.json b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/ja.json index d7104bfd..00dffe3f 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/ja.json +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/ja.json @@ -37,6 +37,7 @@ "BACKGROUND": "背景効果", "START_RECORDING": "録画開始", "STOP_RECORDING": "録画の停止", + "SETTINGS": "設定", "LEAVE": "セッションを終了する", "PARTICIPANTS": "参加者", "CHAT": "チャット", @@ -64,6 +65,13 @@ "CAMERA": "カメラ", "SCREEN": "スクリーン" }, + "SETTINGS": { + "TITLE": "設定", + "GENERAL": "全般的", + "VIDEO": "ビデオ", + "AUDIO": "オーディオ", + "LANGUAGE":"言語" + }, "BACKGROUND": { "TITLE": "背景効果", "BLURRED_SECTION": "エフェクトなし、ぼやけた背景", diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/nl.json b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/nl.json index d60dd683..51c0acb7 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/nl.json +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/nl.json @@ -37,6 +37,7 @@ "BACKGROUND": "Achtergrondeffecten", "START_RECORDING": "Start opname", "STOP_RECORDING": "Stop opname", + "SETTINGS": "Instellingen", "LEAVE": "Verlaat de sessie", "PARTICIPANTS": "Deelnemers", "CHAT": "Chat", @@ -64,6 +65,13 @@ "CAMERA": "CAMERA", "SCREEN": "SCHERM" }, + "SETTINGS": { + "TITLE": "Instellingen", + "GENERAL": "Algemeen", + "VIDEO": "Video", + "AUDIO": "Audio", + "LANGUAGE":"Taal" + }, "BACKGROUND": { "TITLE": "Achtergrondeffecten", "BLURRED_SECTION": "Geen effecten en onscherpe achtergrond", diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/pt.json b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/pt.json index 219b637f..14791649 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/pt.json +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/lang/pt.json @@ -37,6 +37,7 @@ "BACKGROUND": "Efeitos de fundo", "START_RECORDING": "Iniciar_gravação", "STOP_RECORDING": "Parar de gravar", + "SETTINGS": "Configurações", "LEAVE": "Sair da sessão", "PARTICIPANTS": "Participantes", "CHAT": "Chat", @@ -64,6 +65,13 @@ "CAMERA": "CÂMERA", "SCREEN": "TELA" }, + "SETTINGS": { + "TITLE": "Configurações", + "GENERAL": "Em geral", + "VIDEO": "Vídeo", + "AUDIO": "Áudio", + "LANGUAGE":"Linguagem" + }, "BACKGROUND": { "TITLE": "Efeitos de fundo", "BLURRED_SECTION": "Sem efeitos e fundo desfocado", diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/models/panel.model.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/models/panel.model.ts index 3ef2d937..45402f9a 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/models/panel.model.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/models/panel.model.ts @@ -2,6 +2,7 @@ export enum PanelType { CHAT = 'chat', PARTICIPANTS = 'participants', BACKGROUND_EFFECTS = 'background-effects', - ACTIVITIES = 'activities' + ACTIVITIES = 'activities', + SETTINGS = 'settings' } \ No newline at end of file diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/models/participant.model.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/models/participant.model.ts index 3f5b7bf5..1cbff033 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/models/participant.model.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/models/participant.model.ts @@ -95,12 +95,27 @@ export abstract class ParticipantAbstractModel { /** * @internal */ - public isCameraAudioActive(): boolean { + hasAudioActive(): boolean { const cameraConnection = this.getCameraConnection(); - if (cameraConnection) { - return cameraConnection.connected && cameraConnection.streamManager?.stream?.audioActive; + const screenConnection = this.getScreenConnection(); + + if (cameraConnection.connected) { + return this.isCameraAudioActive(); + } else if (screenConnection.connected) { + return this.isScreenAudioActive(); } - return this.isScreenAudioActive(); + return false; + } + + /** + * @internal + */ + private isCameraAudioActive(): boolean { + const cameraConnection = this.getCameraConnection(); + if (cameraConnection?.connected) { + return cameraConnection.streamManager?.stream?.audioActive; + } + return false; } /** @@ -116,8 +131,8 @@ export abstract class ParticipantAbstractModel { */ isScreenAudioActive(): boolean { const screenConnection = this.getScreenConnection(); - if (screenConnection) { - return screenConnection?.connected && screenConnection?.streamManager?.stream?.audioActive; + if (screenConnection?.connected) { + return screenConnection?.streamManager?.stream?.audioActive; } return false; } diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/openvidu-angular.module.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/openvidu-angular.module.ts index dd4a20ad..a9716884 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/openvidu-angular.module.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/openvidu-angular.module.ts @@ -48,11 +48,16 @@ import { AvatarProfileComponent } from './components/avatar-profile/avatar-profi import { OpenViduAngularDirectiveModule } from './directives/template/openvidu-angular.directive.module'; import { ApiDirectiveModule } from './directives/api/api.directive.module'; import { BackgroundEffectsPanelComponent } from './components/panel/background-effects-panel/background-effects-panel.component'; +import { SettingsPanelComponent } from './components/panel/settings-panel/settings-panel.component'; import { ActivitiesPanelComponent } from './components/panel/activities-panel/activities-panel.component'; import { RecordingActivityComponent } from './components/panel/activities-panel/recording-activity-panel/recording-activity.component'; import { AdminDashboardComponent } from './admin/dashboard/dashboard.component'; import { AdminLoginComponent } from './admin/login/login.component'; import { AppMaterialModule } from './openvidu-angular.material.module'; +import { VideoDevicesComponent } from './components/settings/video-devices/video-devices.component'; +import { AudioDevicesComponent } from './components/settings/audio-devices/audio-devices.component'; +import { NicknameInputComponent } from './components/settings/nickname-input/nickname-input.component'; +import { LangSelectorComponent } from './components/settings/lang-selector/lang-selector.component'; @NgModule({ declarations: [ @@ -78,7 +83,12 @@ import { AppMaterialModule } from './openvidu-angular.material.module'; PanelComponent, AvatarProfileComponent, PreJoinComponent, + VideoDevicesComponent, + AudioDevicesComponent, + NicknameInputComponent, + LangSelectorComponent, BackgroundEffectsPanelComponent, + SettingsPanelComponent, ActivitiesPanelComponent, RecordingActivityComponent, AdminDashboardComponent, @@ -118,6 +128,7 @@ import { AppMaterialModule } from './openvidu-angular.material.module'; ParticipantsPanelComponent, ParticipantPanelItemComponent, BackgroundEffectsPanelComponent, + SettingsPanelComponent, ActivitiesPanelComponent, ChatPanelComponent, SessionComponent, diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/config/openvidu-angular.config.service.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/config/openvidu-angular.config.service.ts index 92f82d9c..2c94b12a 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/config/openvidu-angular.config.service.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/config/openvidu-angular.config.service.ts @@ -28,6 +28,9 @@ export class OpenViduAngularConfigService { fullscreenButton = >new BehaviorSubject(true); fullscreenButtonObs: Observable; + toolbarSettingsButton = >new BehaviorSubject(true); + toolbarSettingsButtonObs: Observable; + leaveButton = >new BehaviorSubject(true); leaveButtonObs: Observable; @@ -49,8 +52,8 @@ export class OpenViduAngularConfigService { displayParticipantNameObs: Observable; displayAudioDetection = >new BehaviorSubject(true); displayAudioDetectionObs: Observable; - settingsButton = >new BehaviorSubject(true); - settingsButtonObs: Observable; + streamSettingsButton = >new BehaviorSubject(true); + streamSettingsButtonObs: Observable; participantItemMuteButton = >new BehaviorSubject(true); participantItemMuteButtonObs: Observable; backgroundEffectsButton = >new BehaviorSubject(true); @@ -88,10 +91,11 @@ export class OpenViduAngularConfigService { this.displaySessionNameObs = this.displaySessionName.asObservable(); this.displayLogoObs = this.displayLogo.asObservable(); this.recordingButtonObs = this.recordingButton.asObservable(); + this.toolbarSettingsButtonObs = this.toolbarSettingsButton.asObservable(); //Stream observables this.displayParticipantNameObs = this.displayParticipantName.asObservable(); this.displayAudioDetectionObs = this.displayAudioDetection.asObservable(); - this.settingsButtonObs = this.settingsButton.asObservable(); + this.streamSettingsButtonObs = this.streamSettingsButton.asObservable(); // Participant item observables this.participantItemMuteButtonObs = this.participantItemMuteButton.asObservable(); // Recording activity observables @@ -107,7 +111,7 @@ export class OpenViduAngularConfigService { return this.configuration; } isProduction(): boolean { - return this.configuration?.production; + return this.configuration?.production || false; } hasParticipantFactory(): boolean { diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/device/device.service.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/device/device.service.ts index bf1905b8..741ef318 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/device/device.service.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/device/device.service.ts @@ -39,16 +39,15 @@ export class DeviceService { private libSrv: OpenViduAngularConfigService ) { this.log = this.loggerSrv.get('DevicesService'); - } - async forceUpdate() { - this.cameras = []; - this.microphones = []; - await this.initializeDevices(); - } + // async forceUpdate() { + // await this.initializeDevices(); + // } async initializeDevices() { + this.cameras = []; + this.microphones = []; try { this.OV = new OpenVidu(); // Forcing media permissions request. diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/openvidu/openvidu.service.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/openvidu/openvidu.service.ts index 923adb82..cdc7a36d 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/openvidu/openvidu.service.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/openvidu/openvidu.service.ts @@ -76,6 +76,10 @@ export class OpenViduService { this.ovEdition = edition; } + isSessionConnected(): boolean { + return !!this.webcamSession.connection; + } + /** * @internal */ diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/panel/panel.service.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/panel/panel.service.ts index 7cc17b48..a5c180d5 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/panel/panel.service.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/panel/panel.service.ts @@ -4,6 +4,13 @@ import { ILogger } from '../../models/logger.model'; import { PanelType } from '../../models/panel.model'; import { LoggerService } from '../logger/logger.service'; +export interface PanelEvent { + opened: boolean; + type?: PanelType | string; + expand?: string; + oldType?: PanelType | string; +} + @Injectable({ providedIn: 'root' }) @@ -11,14 +18,15 @@ export class PanelService { /** * Panel Observable which pushes the panel status in every update. */ - panelOpenedObs: Observable<{ opened: boolean; type?: PanelType | string }>; + panelOpenedObs: Observable; protected log: ILogger; protected isChatOpened: boolean = false; protected isParticipantsOpened: boolean = false; protected isActivitiesOpened: boolean = false; private isExternalOpened: boolean = false; private externalType: string; - protected _panelOpened = >new BehaviorSubject({ opened: false }); + protected _panelOpened = >new BehaviorSubject({ opened: false }); + private panelMap: Map = new Map(); /** * @internal @@ -26,6 +34,7 @@ export class PanelService { constructor(protected loggerSrv: LoggerService) { this.log = this.loggerSrv.get('PanelService'); this.panelOpenedObs = this._panelOpened.asObservable(); + Object.values(PanelType).forEach((panel) => this.panelMap.set(panel, false)); } /** @@ -33,45 +42,43 @@ export class PanelService { * If the type is differente, it will switch to the properly panel. */ togglePanel(type: PanelType | string, expand?: string) { - this.log.d(`Toggling ${type} menu`); - let opened: boolean; - if (type === PanelType.CHAT) { - this.isChatOpened = !this.isChatOpened; - this.isParticipantsOpened = false; - this.isExternalOpened = false; - this.isActivitiesOpened = false - opened = this.isChatOpened; - } else if (type === PanelType.PARTICIPANTS) { - this.isParticipantsOpened = !this.isParticipantsOpened; - this.isChatOpened = false; - this.isExternalOpened = false; - this.isActivitiesOpened = false; - opened = this.isParticipantsOpened; - } else if (type === PanelType.ACTIVITIES) { - this.isActivitiesOpened = !this.isActivitiesOpened; - this.isChatOpened = false; - this.isExternalOpened = false; - this.isParticipantsOpened = false; - opened = this.isActivitiesOpened; + let nextOpenedValue: boolean = false; + if (this.panelMap.has(type)) { + this.log.d(`Toggling ${type} menu`); + + this.panelMap.forEach((opened: boolean, panel: string) => { + if (panel === type) { + // Toggle panel + this.panelMap.set(panel, !opened); + nextOpenedValue = !opened; + } else { + // Close others + this.panelMap.set(panel, false); + } + }); } else { + // Panel is external this.log.d('Toggling external panel'); this.isChatOpened = false; this.isParticipantsOpened = false; this.isActivitiesOpened = false; - // Open when is close or is opened with another type + // Open when is closed or is opened with another type this.isExternalOpened = !this.isExternalOpened || this.externalType !== type; this.externalType = !this.isExternalOpened ? '' : type; - opened = this.isExternalOpened; + nextOpenedValue = this.isExternalOpened; } - this._panelOpened.next({ opened, type, expand }); + const oldType = this._panelOpened.getValue().type; + this._panelOpened.next({ opened: nextOpenedValue, type, expand, oldType }); } /** * @internal */ isPanelOpened(): boolean { - return this.isChatPanelOpened() || this.isParticipantsPanelOpened() || this.isActivitiesPanelOpened() || this.isExternalPanelOpened(); + return ( + this.isChatPanelOpened() || this.isParticipantsPanelOpened() || this.isActivitiesPanelOpened() || this.isExternalPanelOpened() + ); } /** @@ -102,7 +109,7 @@ export class PanelService { /** * Whether the activities panel is opened or not. */ - isActivitiesPanelOpened(): boolean { + isActivitiesPanelOpened(): boolean { return this.isActivitiesOpened; } diff --git a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/participant/participant.service.ts b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/participant/participant.service.ts index 2def4632..f4559765 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/lib/services/participant/participant.service.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/lib/services/participant/participant.service.ts @@ -196,7 +196,7 @@ export class ParticipantService { } isMyAudioActive(): boolean { - return this.localParticipant?.isCameraAudioActive() || this.localParticipant?.isScreenAudioActive(); + return this.localParticipant?.hasAudioActive(); } /** diff --git a/openvidu-components-angular/projects/openvidu-angular/src/public-api.ts b/openvidu-components-angular/projects/openvidu-angular/src/public-api.ts index 4af12474..4302763c 100644 --- a/openvidu-components-angular/projects/openvidu-angular/src/public-api.ts +++ b/openvidu-components-angular/projects/openvidu-angular/src/public-api.ts @@ -26,6 +26,7 @@ export * from './lib/components/videoconference/videoconference.component'; export * from './lib/components/toolbar/toolbar.component'; export * from './lib/components/panel/panel.component'; export * from './lib/components/panel/chat-panel/chat-panel.component'; +export * from './lib/components/panel/settings-panel/settings-panel.component'; export * from './lib/components/panel/background-effects-panel/background-effects-panel.component'; export * from './lib/components/panel/activities-panel/activities-panel.component'; export * from './lib/components/panel/participants-panel/participants-panel/participants-panel.component';