mirror of https://github.com/OpenVidu/openvidu.git
openvidu-components: Imrpoved user settings
Fixed some bugs with replacing tracks and devices saved on storage Minor refactoringpull/707/head
parent
b437547501
commit
f40093746f
|
@ -1,4 +1,4 @@
|
|||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
|
||||
|
||||
import { PublisherSpeakingEvent, StreamManager } from 'openvidu-browser';
|
||||
|
||||
|
@ -7,19 +7,22 @@ import { PublisherSpeakingEvent, StreamManager } from 'openvidu-browser';
|
|||
templateUrl: './audio-wave.component.html',
|
||||
styleUrls: ['./audio-wave.component.css']
|
||||
})
|
||||
export class AudioWaveComponent implements OnInit {
|
||||
export class AudioWaveComponent implements OnInit, OnDestroy {
|
||||
isSpeaking: boolean = false;
|
||||
audioVolume: number = 0;
|
||||
|
||||
private _streamManager: StreamManager;
|
||||
|
||||
@Input()
|
||||
set streamManager(streamManager: StreamManager) {
|
||||
this._streamManager = streamManager;
|
||||
|
||||
if(streamManager) {
|
||||
streamManager.on('publisherStartSpeaking', (event: PublisherSpeakingEvent) => {
|
||||
if(this._streamManager) {
|
||||
this._streamManager.on('publisherStartSpeaking', (event: PublisherSpeakingEvent) => {
|
||||
this.isSpeaking = true;
|
||||
});
|
||||
|
||||
streamManager.on('publisherStopSpeaking', (event: PublisherSpeakingEvent) => {
|
||||
this._streamManager.on('publisherStopSpeaking', (event: PublisherSpeakingEvent) => {
|
||||
this.isSpeaking = false;
|
||||
});
|
||||
|
||||
|
@ -35,6 +38,12 @@ export class AudioWaveComponent implements OnInit {
|
|||
}
|
||||
|
||||
constructor() {}
|
||||
ngOnDestroy(): void {
|
||||
if(this._streamManager){
|
||||
this._streamManager.off('publisherStartSpeaking');
|
||||
this._streamManager.off('publisherStopSpeaking');
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit(): void {}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
[id]="'container-' + this._stream.streamManager?.stream?.streamId"
|
||||
#streamContainer
|
||||
>
|
||||
<div class="nickname" [class.fullscreen]="isFullscreen">
|
||||
<div class="nickname" [class.fullscreen]="isFullscreen" *ngIf="showNickname">
|
||||
<div (click)="toggleNicknameForm()" class="nicknameContainer" selected *ngIf="!toggleNickname">
|
||||
<span id="nickname">{{ this._stream.nickname }}</span>
|
||||
<span *ngIf="_stream.local || (_stream.streamManager && !_stream.streamManager?.remote)"> (edit)</span>
|
||||
|
@ -31,7 +31,7 @@
|
|||
<ng-content select="[network-quality]"></ng-content>
|
||||
</div>
|
||||
|
||||
<div id="audio-wave-container" *ngIf="_stream.type === 'CAMERA'">
|
||||
<div id="audio-wave-container" *ngIf="showAudioDetection && _stream.type === 'CAMERA'">
|
||||
<ov-audio-wave [streamManager]="_stream.streamManager"></ov-audio-wave>
|
||||
</div>
|
||||
|
||||
|
@ -49,7 +49,7 @@
|
|||
</button>
|
||||
</div>
|
||||
|
||||
<div class="videoButtons">
|
||||
<div class="videoButtons" *ngIf="showSettings">
|
||||
|
||||
<button mat-icon-button (click)="toggleVideoMenu($event)" matTooltip="Settings" aria-label="Video settings menu">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
|
|
|
@ -34,6 +34,10 @@ export class StreamComponent implements OnInit {
|
|||
@ViewChild(MatMenuTrigger) public menuTrigger: MatMenuTrigger;
|
||||
@ViewChild('menu') menu: MatMenuPanel;
|
||||
|
||||
@Input() showNickname: boolean = true;
|
||||
@Input() showAudioDetection: boolean = true;
|
||||
@Input() showSettings: boolean = true;
|
||||
|
||||
constructor(
|
||||
protected documentService: DocumentService,
|
||||
protected openviduService: OpenViduService,
|
||||
|
@ -128,7 +132,7 @@ export class StreamComponent implements OnInit {
|
|||
if (event && event.keyCode === 13 && this.nicknameFormControl.valid) {
|
||||
const nickname = this.nicknameFormControl.value;
|
||||
this.participantService.setNickname(this._stream.connectionId, nickname);
|
||||
this.storageService.set(Storage.USER_NICKNAME, nickname);
|
||||
this.storageService.setNickname(nickname);
|
||||
this.openviduService.sendSignal(Signal.NICKNAME_CHANGED, undefined, { clientData: nickname });
|
||||
this.toggleNicknameForm();
|
||||
}
|
||||
|
@ -141,7 +145,7 @@ export class StreamComponent implements OnInit {
|
|||
publishAudio: !this.participantService.isMyCameraEnabled(),
|
||||
mirror: false
|
||||
};
|
||||
await this.openviduService.replaceTrack(this.participantService.getMyScreenPublisher(), properties);
|
||||
await this.openviduService.replaceTrack(VideoType.SCREEN, properties);
|
||||
}
|
||||
|
||||
protected checkVideoEnlarged() {
|
||||
|
|
|
@ -44,17 +44,6 @@
|
|||
<mat-icon *ngIf="isScreenShareEnabled" matTooltip="Disable screen share">screen_share</mat-icon>
|
||||
</button>
|
||||
|
||||
<!-- Replace Screen track button -->
|
||||
<!-- <button
|
||||
id="navReplaceScreenButton"
|
||||
mat-icon-button
|
||||
*ngIf="isScreenShareEnabled"
|
||||
(click)="replaceScreenTrack()"
|
||||
[disabled]="isConnectionLost"
|
||||
>
|
||||
<mat-icon matTooltip="Replace screen track">picture_in_picture</mat-icon>
|
||||
</button> -->
|
||||
|
||||
<!-- Fullscreen button -->
|
||||
<button mat-icon-button (click)="toggleFullscreen()" [disabled]="isConnectionLost" [class.active-btn]="isFullscreenEnabled">
|
||||
<mat-icon *ngIf="isFullscreenEnabled" matTooltip="Exit Fullscreen">fullscreen_exit</mat-icon>
|
||||
|
|
|
@ -173,7 +173,7 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
publishAudio: hasAudio,
|
||||
mirror: false
|
||||
};
|
||||
const screenPublisher = this.openviduService.initPublisher(undefined, properties);
|
||||
const screenPublisher = await this.openviduService.initPublisher(undefined, properties);
|
||||
|
||||
screenPublisher.once('accessAllowed', async (event) => {
|
||||
// Listen to event fired when native stop button is clicked
|
||||
|
@ -225,16 +225,6 @@ export class ToolbarComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
|
||||
async replaceScreenTrack() {
|
||||
const properties: PublisherProperties = {
|
||||
videoSource: ScreenType.SCREEN,
|
||||
publishVideo: true,
|
||||
publishAudio: !this.participantService.isMyCameraEnabled(),
|
||||
mirror: false
|
||||
};
|
||||
await this.openviduService.replaceTrack(this.participantService.getMyScreenPublisher(), properties);
|
||||
}
|
||||
|
||||
leaveSession() {
|
||||
this.log.d('Leaving session...');
|
||||
this.openviduService.disconnect();
|
||||
|
|
|
@ -48,17 +48,17 @@
|
|||
(click)="toggleCam()"
|
||||
class="deviceButton"
|
||||
id="configCardCameraButton"
|
||||
[class.warn-btn]="!isVideoActive"
|
||||
[class.warn-btn]="isVideoMuted"
|
||||
>
|
||||
<mat-icon *ngIf="isVideoActive" matTooltip="Camera Enabled">videocam</mat-icon>
|
||||
<mat-icon *ngIf="!isVideoActive" matTooltip="Camera Disabled">videocam_off</mat-icon>
|
||||
<mat-icon *ngIf="!isVideoMuted" matTooltip="Camera Enabled">videocam</mat-icon>
|
||||
<mat-icon *ngIf="isVideoMuted" matTooltip="Camera Disabled">videocam_off</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="two" fxFlex="80" fxLayoutAlign="center center">
|
||||
<mat-form-field class="alternate-theme">
|
||||
<mat-select
|
||||
placeholder="Camera Options"
|
||||
[ngModel]="isVideoActive && !!cameraSelected ? cameraSelected.device : 'None'"
|
||||
[ngModel]="!isVideoMuted && !!cameraSelected ? cameraSelected.device : 'None'"
|
||||
(selectionChange)="onCameraSelected($event)"
|
||||
>
|
||||
<mat-option *ngFor="let camera of cameras" [value]="camera.device">
|
||||
|
@ -78,17 +78,17 @@
|
|||
(click)="toggleMic()"
|
||||
class="deviceButton"
|
||||
id="configCardMicrophoneButton"
|
||||
[class.warn-btn]="!isAudioActive"
|
||||
[class.warn-btn]="isAudioMuted"
|
||||
>
|
||||
<mat-icon *ngIf="isAudioActive" matTooltip="Microphone Enabled">mic</mat-icon>
|
||||
<mat-icon *ngIf="!isAudioActive" matTooltip="Microphone Disabled">mic_off</mat-icon>
|
||||
<mat-icon *ngIf="!isAudioMuted" matTooltip="Microphone Enabled">mic</mat-icon>
|
||||
<mat-icon *ngIf="isAudioMuted" matTooltip="Microphone Disabled">mic_off</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="two" fxFlex="80" fxLayoutAlign="center center">
|
||||
<mat-form-field class="alternate-theme">
|
||||
<mat-select
|
||||
placeholder="Microphone Options"
|
||||
[ngModel]="isAudioActive && microphoneSelected ? microphoneSelected.device : 'None'"
|
||||
[ngModel]="!isAudioMuted && microphoneSelected ? microphoneSelected.device : 'None'"
|
||||
(selectionChange)="onMicrophoneSelected($event)"
|
||||
>
|
||||
<mat-option *ngFor="let microphone of microphones" [value]="microphone.device">
|
||||
|
|
|
@ -7,8 +7,7 @@ import { Publisher, PublisherProperties } from 'openvidu-browser';
|
|||
|
||||
import { ILogger } from '../../models/logger.model';
|
||||
import { CustomDevice } from '../../models/device.model';
|
||||
import { Storage } from '../../models/storage.model';
|
||||
import { ScreenType } from '../../models/video-type.model';
|
||||
import { ScreenType, VideoType } from '../../models/video-type.model';
|
||||
|
||||
import { NicknameMatcher } from '../../matchers/nickname.matcher';
|
||||
|
||||
|
@ -36,8 +35,8 @@ export class UserSettingsComponent implements OnInit, OnDestroy {
|
|||
microphones: CustomDevice[];
|
||||
cameraSelected: CustomDevice;
|
||||
microphoneSelected: CustomDevice;
|
||||
isVideoActive = true;
|
||||
isAudioActive = true;
|
||||
isVideoMuted: boolean;
|
||||
isAudioMuted: boolean;
|
||||
screenShareEnabled: boolean;
|
||||
localParticipant: ParticipantAbstractModel;
|
||||
columns: number;
|
||||
|
@ -55,7 +54,7 @@ export class UserSettingsComponent implements OnInit, OnDestroy {
|
|||
private actionService: ActionService,
|
||||
private deviceSrv: DeviceService,
|
||||
private loggerSrv: LoggerService,
|
||||
private openViduopenviduService: OpenViduService,
|
||||
private openviduService: OpenViduService,
|
||||
private participantService: ParticipantService,
|
||||
private storageSrv: StorageService
|
||||
) {
|
||||
|
@ -68,10 +67,11 @@ export class UserSettingsComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.subscribeToLocalParticipantEvents();
|
||||
this.openViduopenviduService.initialize();
|
||||
await this.deviceSrv.initializeDevices();
|
||||
const nickname = this.storageSrv.get(Storage.USER_NICKNAME) || this.generateRandomNickname();
|
||||
|
||||
this.subscribeToLocalParticipantEvents();
|
||||
this.openviduService.initialize();
|
||||
const nickname = this.storageSrv.getNickname() || this.generateRandomNickname();
|
||||
this.nicknameFormControl.setValue(nickname);
|
||||
this.columns = window.innerWidth > 900 ? 2 : 1;
|
||||
this.setDevicesInfo();
|
||||
|
@ -79,7 +79,6 @@ export class UserSettingsComponent implements OnInit, OnDestroy {
|
|||
await this.initwebcamPublisher();
|
||||
}
|
||||
this.isLoading = false;
|
||||
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
|
@ -95,63 +94,57 @@ export class UserSettingsComponent implements OnInit, OnDestroy {
|
|||
|
||||
async onCameraSelected(event: any) {
|
||||
const videoSource = event?.value;
|
||||
if (!!videoSource) {
|
||||
// Is New deviceId different from the old one?
|
||||
if (this.deviceSrv.needUpdateVideoTrack(videoSource)) {
|
||||
const mirror = this.deviceSrv.cameraNeedsMirror(videoSource);
|
||||
await this.openViduopenviduService.republishTrack(videoSource, null, mirror);
|
||||
this.deviceSrv.setCameraSelected(videoSource);
|
||||
this.cameraSelected = this.deviceSrv.getCameraSelected();
|
||||
}
|
||||
// Publish Webcam video
|
||||
this.openViduopenviduService.publishVideo(this.participantService.getMyCameraPublisher(), true);
|
||||
this.isVideoActive = true;
|
||||
// Is New deviceId different from the old one?
|
||||
if (this.deviceSrv.needUpdateVideoTrack(videoSource)) {
|
||||
const mirror = this.deviceSrv.cameraNeedsMirror(videoSource);
|
||||
const pp: PublisherProperties = { videoSource, audioSource: false, mirror };
|
||||
|
||||
} else {
|
||||
// Videosource is 'null' because of the user has selected 'None' or muted the camera
|
||||
// Unpublish webcam
|
||||
this.openViduopenviduService.publishVideo(this.participantService.getMyCameraPublisher(), false);
|
||||
//TODO: save 'None' device in storage
|
||||
// this.deviceSrv.setCameraSelected(videoSource);
|
||||
// this.cameraSelected = this.deviceSrv.getCameraSelected();
|
||||
this.isVideoActive = false;
|
||||
await this.openviduService.replaceTrack(VideoType.CAMERA, pp);
|
||||
this.cameraSelected = videoSource;
|
||||
this.deviceSrv.setCameraSelected(this.cameraSelected);
|
||||
}
|
||||
if (this.isVideoMuted) {
|
||||
// Publish Webcam video
|
||||
this.openviduService.publishVideo(this.participantService.getMyCameraPublisher(), true);
|
||||
this.isVideoMuted = false;
|
||||
}
|
||||
}
|
||||
|
||||
async onMicrophoneSelected(event: any) {
|
||||
const audioSource = event?.value;
|
||||
|
||||
if (!!audioSource) {
|
||||
// Is New deviceId different than older?
|
||||
if (this.deviceSrv.needUpdateAudioTrack(audioSource)) {
|
||||
const mirror = this.deviceSrv.cameraNeedsMirror(this.cameraSelected.device);
|
||||
await this.openViduopenviduService.republishTrack(null, audioSource, mirror);
|
||||
this.deviceSrv.setMicSelected(audioSource);
|
||||
this.microphoneSelected = this.deviceSrv.getMicrophoneSelected();
|
||||
}
|
||||
// Publish microphone
|
||||
this.publishAudio(true);
|
||||
this.isAudioActive = true;
|
||||
return;
|
||||
// Is New deviceId different than older?
|
||||
if (this.deviceSrv.needUpdateAudioTrack(audioSource)) {
|
||||
const pp: PublisherProperties = { audioSource, videoSource: false };
|
||||
await this.openviduService.replaceTrack(VideoType.CAMERA, pp);
|
||||
this.microphoneSelected = audioSource;
|
||||
this.deviceSrv.setMicSelected(this.microphoneSelected);
|
||||
}
|
||||
if (this.isAudioMuted) {
|
||||
// Enable microphone
|
||||
this.openviduService.publishAudio(this.participantService.getMyCameraPublisher(), true);
|
||||
this.isAudioMuted = true;
|
||||
}
|
||||
// Unpublish microhpone
|
||||
this.publishAudio(false);
|
||||
this.isAudioActive = false;
|
||||
}
|
||||
|
||||
toggleCam() {
|
||||
this.isVideoActive = !this.isVideoActive;
|
||||
this.openViduopenviduService.publishVideo(this.participantService.getMyCameraPublisher(), this.isVideoActive);
|
||||
|
||||
const publish = this.isVideoMuted;
|
||||
this.openviduService.publishVideo(this.participantService.getMyCameraPublisher(), publish);
|
||||
|
||||
if (this.participantService.areBothEnabled()) {
|
||||
// Cam will not published, disable webcam with screensharing active
|
||||
this.participantService.disableWebcamUser();
|
||||
this.openViduopenviduService.publishAudio(this.participantService.getMyScreenPublisher(), this.isAudioActive);
|
||||
this.openviduService.publishAudio(this.participantService.getMyScreenPublisher(), publish);
|
||||
} else if (this.participantService.isOnlyMyScreenEnabled()) {
|
||||
// Cam will be published, enable webcam
|
||||
this.participantService.enableWebcamUser();
|
||||
}
|
||||
|
||||
this.isVideoMuted = !this.isVideoMuted;
|
||||
this.storageSrv.setVideoMuted(this.isVideoMuted);
|
||||
}
|
||||
|
||||
toggleScreenShare() {
|
||||
async toggleScreenShare() {
|
||||
// Disabling screenShare
|
||||
if (this.participantService.areBothEnabled()) {
|
||||
this.participantService.disableScreenUser();
|
||||
|
@ -161,7 +154,7 @@ export class UserSettingsComponent implements OnInit, OnDestroy {
|
|||
// Enabling screenShare
|
||||
if (this.participantService.isOnlyMyCameraEnabled()) {
|
||||
const willThereBeWebcam = this.participantService.isMyCameraEnabled() && this.participantService.hasCameraVideoActive();
|
||||
const hasAudio = willThereBeWebcam ? false : this.hasAudioDevices && this.isAudioActive;
|
||||
const hasAudio = willThereBeWebcam ? false : this.hasAudioDevices && this.isAudioMuted;
|
||||
const properties: PublisherProperties = {
|
||||
videoSource: ScreenType.SCREEN,
|
||||
audioSource: this.hasAudioDevices ? undefined : null,
|
||||
|
@ -169,7 +162,7 @@ export class UserSettingsComponent implements OnInit, OnDestroy {
|
|||
publishAudio: hasAudio,
|
||||
mirror: false
|
||||
};
|
||||
const screenPublisher = this.openViduopenviduService.initPublisher(undefined, properties);
|
||||
const screenPublisher = await this.openviduService.initPublisher(undefined, properties);
|
||||
|
||||
screenPublisher.on('accessAllowed', (event) => {
|
||||
screenPublisher.stream
|
||||
|
@ -199,8 +192,10 @@ export class UserSettingsComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
toggleMic() {
|
||||
this.isAudioActive = !this.isAudioActive;
|
||||
this.publishAudio(this.isAudioActive);
|
||||
const publish = this.isAudioMuted;
|
||||
this.openviduService.publishAudio(this.participantService.getMyCameraPublisher(), publish);
|
||||
this.isAudioMuted = !this.isAudioMuted;
|
||||
this.storageSrv.setAudioMuted(this.isAudioMuted);
|
||||
}
|
||||
|
||||
eventKeyPress(event) {
|
||||
|
@ -217,7 +212,8 @@ export class UserSettingsComponent implements OnInit, OnDestroy {
|
|||
if (this.nicknameFormControl.valid) {
|
||||
const nickname = this.nicknameFormControl.value;
|
||||
this.participantService.setNickname(this.participantService.getMyCameraConnectionId(), nickname);
|
||||
this.storageSrv.set(Storage.USER_NICKNAME, nickname);
|
||||
this.storageSrv.setNickname(nickname);
|
||||
this.participantService.updateParticipantMediaStatus();
|
||||
return this.onJoinClicked.emit();
|
||||
}
|
||||
this.scrollToBottom();
|
||||
|
@ -235,9 +231,8 @@ export class UserSettingsComponent implements OnInit, OnDestroy {
|
|||
this.cameraSelected = this.deviceSrv.getCameraSelected();
|
||||
this.microphoneSelected = this.deviceSrv.getMicrophoneSelected();
|
||||
|
||||
this.isVideoActive = this.hasVideoDevices && this.cameraSelected.label !== 'None';
|
||||
this.isAudioActive = this.hasAudioDevices && this.microphoneSelected.label !== 'None';
|
||||
|
||||
this.isVideoMuted = this.deviceSrv.isVideoMuted();
|
||||
this.isAudioMuted = this.deviceSrv.isAudioMuted();
|
||||
}
|
||||
|
||||
private scrollToBottom(): void {
|
||||
|
@ -246,12 +241,6 @@ export class UserSettingsComponent implements OnInit, OnDestroy {
|
|||
} catch (err) {}
|
||||
}
|
||||
|
||||
private publishAudio(audio: boolean) {
|
||||
this.participantService.isMyCameraEnabled()
|
||||
? this.openViduopenviduService.publishAudio(this.participantService.getMyCameraPublisher(), audio)
|
||||
: this.openViduopenviduService.publishAudio(this.participantService.getMyScreenPublisher(), audio);
|
||||
}
|
||||
|
||||
private subscribeToLocalParticipantEvents() {
|
||||
this.oVUsersSubscription = this.participantService.localParticipantObs.subscribe((p) => {
|
||||
this.localParticipant = p;
|
||||
|
@ -262,9 +251,8 @@ export class UserSettingsComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
private async initwebcamPublisher() {
|
||||
const publisher = await this.openViduopenviduService.initDefaultPublisher(undefined);
|
||||
const publisher = await this.openviduService.initDefaultPublisher(undefined);
|
||||
if (publisher) {
|
||||
|
||||
// this.handlePublisherSuccess(publisher);
|
||||
this.handlePublisherError(publisher);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
export enum Storage{
|
||||
USER_NICKNAME = 'openviduCallNickname',
|
||||
VIDEO_DEVICE = 'openviduCallVideoDevice',
|
||||
AUDIO_DEVICE = 'openviduCallAudioDevice'
|
||||
AUDIO_DEVICE = 'openviduCallAudioDevice',
|
||||
AUDIO_MUTED = 'openviduCallAudioMuted',
|
||||
VIDEO_MUTED = 'openviduCallVideoMuted'
|
||||
}
|
|
@ -3,7 +3,6 @@ import { Device, OpenVidu } from 'openvidu-browser';
|
|||
|
||||
import { CameraType, DeviceType, CustomDevice } from '../../models/device.model';
|
||||
import { ILogger } from '../../models/logger.model';
|
||||
import { Storage } from '../../models/storage.model';
|
||||
|
||||
import { LoggerService } from '../logger/logger.service';
|
||||
import { PlatformService } from '../platform/platform.service';
|
||||
|
@ -23,6 +22,11 @@ export class DeviceService {
|
|||
private videoDevicesDisabled: boolean;
|
||||
private audioDevicesDisabled: boolean;
|
||||
|
||||
// Initialized with Storage.VIDEO_MUTED info saved on storage
|
||||
private _isVideoMuted: boolean;
|
||||
// Initialized with Storage.AUDIO_MUTED info saved on storage
|
||||
private _isAudioMuted: boolean;
|
||||
|
||||
constructor(private loggerSrv: LoggerService, private platformSrv: PlatformService, private storageSrv: StorageService) {
|
||||
this.log = this.loggerSrv.get('DevicesService');
|
||||
this.OV = new OpenVidu();
|
||||
|
@ -33,18 +37,21 @@ export class DeviceService {
|
|||
}
|
||||
|
||||
async initializeDevices() {
|
||||
// Requesting media permissions. Sometimes, browser doens't launch the media permissions modal.
|
||||
const mediaStream = await this.OV.getUserMedia({audioSource: undefined, videoSource: undefined });
|
||||
// Forcing media permissions request.
|
||||
// Sometimes, browser doens't launch the media permissions modal.
|
||||
const mediaStream = await this.OV.getUserMedia({ audioSource: undefined, videoSource: undefined });
|
||||
mediaStream?.getAudioTracks().forEach((track) => track.stop());
|
||||
mediaStream?.getVideoTracks().forEach((track) => track.stop());
|
||||
|
||||
this.devices = await this.OV.getDevices();
|
||||
const customDevices = this.initializeCustomDevices(this.devices);
|
||||
this.cameras = customDevices.cameras;
|
||||
this.microphones = customDevices.microphones;
|
||||
|
||||
mediaStream?.getAudioTracks().forEach((track) => track.stop());
|
||||
mediaStream?.getVideoTracks().forEach((track) => track.stop());
|
||||
this._isVideoMuted = this.storageSrv.isVideoMuted();
|
||||
this._isAudioMuted = this.storageSrv.isAudioMuted();
|
||||
|
||||
this.log.d('Media devices',customDevices);
|
||||
this.log.d('Media devices', customDevices);
|
||||
}
|
||||
|
||||
private initializeCustomDevices(defaultVDevices: Device[]) {
|
||||
|
@ -52,8 +59,8 @@ export class DeviceService {
|
|||
const defaultMicrophones = defaultVDevices.filter((device) => device.kind === DeviceType.AUDIO_INPUT);
|
||||
const defaultCameras = defaultVDevices.filter((device) => device.kind === DeviceType.VIDEO_INPUT);
|
||||
const customDevices: { cameras: CustomDevice[]; microphones: CustomDevice[] } = {
|
||||
cameras: [{ label: 'None', device: null, type: null }],
|
||||
microphones: [{ label: 'None', device: null, type: null }]
|
||||
cameras: [],
|
||||
microphones: []
|
||||
};
|
||||
|
||||
if (this.hasAudioDeviceAvailable) {
|
||||
|
@ -61,12 +68,12 @@ export class DeviceService {
|
|||
customDevices.microphones.push({ label: device.label, device: device.deviceId });
|
||||
});
|
||||
|
||||
// Settings microphone selected
|
||||
// Setting microphone selected
|
||||
const storageMicrophone = this.getMicrophoneFromStogare();
|
||||
if (!!storageMicrophone) {
|
||||
this.microphoneSelected = storageMicrophone;
|
||||
} else if (customDevices.microphones.length > 0) {
|
||||
this.microphoneSelected = customDevices.microphones.find((d) => d.label !== 'None');
|
||||
this.microphoneSelected = customDevices.microphones[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,12 +103,20 @@ export class DeviceService {
|
|||
if (!!storageCamera) {
|
||||
this.cameraSelected = storageCamera;
|
||||
} else if (customDevices.cameras.length > 0) {
|
||||
this.cameraSelected = customDevices.cameras.find((d) => d.label !== 'None');
|
||||
this.cameraSelected = customDevices.cameras[0];
|
||||
}
|
||||
}
|
||||
return customDevices;
|
||||
}
|
||||
|
||||
isVideoMuted(): boolean {
|
||||
return this.hasVideoDeviceAvailable() && this._isVideoMuted;
|
||||
}
|
||||
|
||||
isAudioMuted(): boolean {
|
||||
return this.hasAudioDeviceAvailable() && this._isAudioMuted;
|
||||
}
|
||||
|
||||
getCameraSelected(): CustomDevice {
|
||||
return this.cameraSelected;
|
||||
}
|
||||
|
@ -137,11 +152,11 @@ export class DeviceService {
|
|||
}
|
||||
|
||||
hasVideoDeviceAvailable(): boolean {
|
||||
return !this.videoDevicesDisabled && !this.cameras.every((device) => device.label === 'None');
|
||||
return !this.videoDevicesDisabled && this.cameras.length > 0;
|
||||
}
|
||||
|
||||
hasAudioDeviceAvailable(): boolean {
|
||||
return !this.audioDevicesDisabled && !this.microphones.every((device) => device.label === 'None');
|
||||
return !this.audioDevicesDisabled && this.microphones.length > 0;
|
||||
}
|
||||
|
||||
cameraNeedsMirror(deviceField: string): boolean {
|
||||
|
@ -180,24 +195,24 @@ export class DeviceService {
|
|||
}
|
||||
|
||||
private getMicrophoneFromStogare(): CustomDevice {
|
||||
let storageDevice = this.storageSrv.get(Storage.AUDIO_DEVICE);
|
||||
if (!!storageDevice) {
|
||||
const storageDevice: CustomDevice = this.storageSrv.getAudioDevice();
|
||||
if (!!storageDevice && this.microphones.some((device) => device.device === storageDevice.device)) {
|
||||
return storageDevice;
|
||||
}
|
||||
}
|
||||
|
||||
private getCameraFromStorage() {
|
||||
let storageDevice = this.storageSrv.get(Storage.VIDEO_DEVICE);
|
||||
if (!!storageDevice) {
|
||||
const storageDevice: CustomDevice = this.storageSrv.getVideoDevice();
|
||||
if (!!storageDevice && this.cameras.some((device) => device.device === storageDevice.device)) {
|
||||
return storageDevice;
|
||||
}
|
||||
}
|
||||
|
||||
private saveCameraToStorage(cam: CustomDevice) {
|
||||
this.storageSrv.set(Storage.VIDEO_DEVICE, cam);
|
||||
this.storageSrv.setVideoDevice(cam);
|
||||
}
|
||||
|
||||
private saveMicrophoneToStorage(mic: CustomDevice) {
|
||||
this.storageSrv.set(Storage.AUDIO_DEVICE, mic);
|
||||
this.storageSrv.setAudioDevice(mic);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,8 +22,8 @@ export class OpenViduService {
|
|||
protected screenSession: Session = null;
|
||||
protected videoSource = undefined;
|
||||
protected audioSource = undefined;
|
||||
protected screenMediaStream: MediaStream = null;
|
||||
protected webcamMediaStream: MediaStream = null;
|
||||
// protected screenMediaStream: MediaStream = null;
|
||||
// protected webcamMediaStream: MediaStream = null;
|
||||
protected log: ILogger;
|
||||
|
||||
constructor(
|
||||
|
@ -49,6 +49,10 @@ export class OpenViduService {
|
|||
}
|
||||
}
|
||||
|
||||
getSession(): Session {
|
||||
return this.getWebcamSession();
|
||||
}
|
||||
|
||||
getWebcamSession(): Session {
|
||||
return this.webcamSession;
|
||||
}
|
||||
|
@ -90,60 +94,44 @@ export class OpenViduService {
|
|||
}
|
||||
}
|
||||
|
||||
private disconnectSession(session: Session) {
|
||||
if (session) {
|
||||
if (session.sessionId === this.webcamSession?.sessionId) {
|
||||
this.log.d('Disconnecting webcam session');
|
||||
this.webcamSession?.disconnect();
|
||||
this.webcamSession = null;
|
||||
} else if (session.sessionId === this.screenSession?.sessionId) {
|
||||
this.log.d('Disconnecting screen session');
|
||||
this.screenSession?.disconnect();
|
||||
this.screenSession = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
this.disconnectSession(this.webcamSession);
|
||||
this.disconnectSession(this.screenSession);
|
||||
this.videoSource = undefined;
|
||||
this.audioSource = undefined;
|
||||
this.stopTracks(this.participantService.getMyCameraPublisher()?.stream?.getMediaStream());
|
||||
this.stopTracks(this.participantService.getMyScreenPublisher()?.stream?.getMediaStream());
|
||||
// this.stopTracks(this.participantService.getMyCameraPublisher()?.stream?.getMediaStream());
|
||||
// this.stopTracks(this.participantService.getMyScreenPublisher()?.stream?.getMediaStream());
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a publisher checking devices saved on storage or if participant have devices available.
|
||||
*/
|
||||
async initDefaultPublisher(targetElement: string | HTMLElement): Promise<Publisher> {
|
||||
await this.deviceService.initializeDevices();
|
||||
|
||||
const hasVideoDevices = this.deviceService.hasVideoDeviceAvailable();
|
||||
const hasAudioDevices = this.deviceService.hasAudioDeviceAvailable();
|
||||
const isVideoActive = hasVideoDevices && this.deviceService.getCameraSelected().label !== 'None';
|
||||
const isAudioActive = hasAudioDevices && this.deviceService.getMicrophoneSelected().label !== 'None';
|
||||
const isVideoActive = !this.deviceService.isVideoMuted();
|
||||
const isAudioActive = !this.deviceService.isAudioMuted();
|
||||
|
||||
let videoSource = null;
|
||||
let audioSource = null;
|
||||
|
||||
if(isVideoActive){
|
||||
if (hasVideoDevices) {
|
||||
// Video is active, assign the device selected
|
||||
videoSource = this.deviceService.getCameraSelected().device
|
||||
} else if(!isVideoActive && hasVideoDevices) {
|
||||
videoSource = this.deviceService.getCameraSelected().device;
|
||||
} else if (!isVideoActive && hasVideoDevices) {
|
||||
// Video is muted, assign the default device
|
||||
videoSource = undefined;
|
||||
// videoSource = undefined;
|
||||
}
|
||||
|
||||
if(isAudioActive){
|
||||
if (hasAudioDevices) {
|
||||
// Audio is active, assign the device selected
|
||||
audioSource = this.deviceService.getMicrophoneSelected().device
|
||||
} else if(!isAudioActive && hasAudioDevices) {
|
||||
audioSource = this.deviceService.getMicrophoneSelected().device;
|
||||
} else if (!isAudioActive && hasAudioDevices) {
|
||||
// Audio is muted, assign the default device
|
||||
audioSource = undefined;
|
||||
// audioSource = undefined;
|
||||
}
|
||||
|
||||
|
||||
// const videoSource = publishVideo ? this.deviceService.getCameraSelected().device : false;
|
||||
// const audioSource = publishAudio ? this.deviceService.getMicrophoneSelected().device : false;
|
||||
const mirror = this.deviceService.getCameraSelected() && this.deviceService.getCameraSelected().type === CameraType.FRONT;
|
||||
|
@ -154,8 +142,8 @@ export class OpenViduService {
|
|||
publishAudio: isAudioActive,
|
||||
mirror
|
||||
};
|
||||
if (isVideoActive || isAudioActive) {
|
||||
const publisher = this.initPublisher(targetElement, properties);
|
||||
if (hasVideoDevices || hasAudioDevices) {
|
||||
const publisher = await this.initPublisher(targetElement, properties);
|
||||
this.participantService.setMyCameraPublisher(publisher);
|
||||
return publisher;
|
||||
} else {
|
||||
|
@ -163,10 +151,10 @@ export class OpenViduService {
|
|||
}
|
||||
}
|
||||
|
||||
initPublisher(targetElement: string | HTMLElement, properties: PublisherProperties): Publisher {
|
||||
async initPublisher(targetElement: string | HTMLElement, properties: PublisherProperties): Promise<Publisher> {
|
||||
this.log.d('Initializing publisher with properties: ', properties);
|
||||
|
||||
const publisher = this.OV.initPublisher(targetElement, properties);
|
||||
const publisher = await this.OV.initPublisherAsync(targetElement, properties);
|
||||
// this.participantService.setMyCameraPublisher(publisher);
|
||||
publisher.once('streamPlaying', () => {
|
||||
(<HTMLElement>publisher.videos[0].video).parentElement.classList.remove('custom-class');
|
||||
|
@ -174,21 +162,21 @@ export class OpenViduService {
|
|||
return publisher;
|
||||
}
|
||||
|
||||
//TODO: This method is used by replaceTrack. Check if it's neecessary
|
||||
private destroyPublisher(publisher: Publisher): void {
|
||||
if (!!publisher) {
|
||||
// publisher.off('streamAudioVolumeChange');
|
||||
if (publisher.stream.getWebRtcPeer()) {
|
||||
publisher.stream.disposeWebRtcPeer();
|
||||
}
|
||||
publisher.stream.disposeMediaStream();
|
||||
if (publisher.id === this.participantService.getMyCameraPublisher().id) {
|
||||
this.participantService.setMyCameraPublisher(publisher);
|
||||
} else if (publisher.id === this.participantService.getMyScreenPublisher().id) {
|
||||
this.participantService.setMyScreenPublisher(publisher);
|
||||
}
|
||||
}
|
||||
}
|
||||
//TODO: This method is used by republishTrack. Check if it's neecessary
|
||||
// private destroyPublisher(publisher: Publisher): void {
|
||||
// if (!!publisher) {
|
||||
// // publisher.off('streamAudioVolumeChange');
|
||||
// if (publisher.stream.getWebRtcPeer()) {
|
||||
// publisher.stream.disposeWebRtcPeer();
|
||||
// }
|
||||
// publisher.stream.disposeMediaStream();
|
||||
// if (publisher.id === this.participantService.getMyCameraPublisher().id) {
|
||||
// this.participantService.setMyCameraPublisher(publisher);
|
||||
// } else if (publisher.id === this.participantService.getMyScreenPublisher().id) {
|
||||
// this.participantService.setMyScreenPublisher(publisher);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
async publish(publisher: Publisher): Promise<void> {
|
||||
if (!!publisher) {
|
||||
|
@ -221,7 +209,7 @@ export class OpenViduService {
|
|||
if (!!publisher) {
|
||||
publisher.publishVideo(value);
|
||||
// Send event to subscribers because of video has changed and view must update
|
||||
this.participantService.updateUsersStatus();
|
||||
this.participantService.updateParticipantMediaStatus();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -229,44 +217,43 @@ export class OpenViduService {
|
|||
if (!!publisher) {
|
||||
publisher.publishAudio(value);
|
||||
// Send event to subscribers because of video has changed and view must update
|
||||
this.participantService.updateUsersStatus();
|
||||
this.participantService.updateParticipantMediaStatus();
|
||||
}
|
||||
}
|
||||
|
||||
republishTrack(videoSource: string, audioSource: string, mirror: boolean = true): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!!videoSource) {
|
||||
this.log.d('Replacing video track ' + videoSource);
|
||||
this.videoSource = videoSource;
|
||||
// this.stopVideoTracks(this.webcamUser.getStreamManager().stream.getMediaStream());
|
||||
}
|
||||
if (!!audioSource) {
|
||||
this.log.d('Replacing audio track ' + audioSource);
|
||||
this.audioSource = audioSource;
|
||||
// this.stopAudioTracks(this.webcamUser.getStreamManager().stream.getMediaStream());
|
||||
}
|
||||
this.destroyPublisher(this.participantService.getMyCameraPublisher());
|
||||
const properties: PublisherProperties = {
|
||||
videoSource: this.videoSource,
|
||||
audioSource: this.audioSource,
|
||||
publishVideo: this.participantService.hasCameraVideoActive(),
|
||||
publishAudio: this.participantService.hasCameraAudioActive(),
|
||||
mirror
|
||||
};
|
||||
// Used replaceTrack instead
|
||||
// republishTrack(videoSource: string, audioSource: string, mirror: boolean = true): Promise<void> {
|
||||
// return new Promise(async (resolve, reject) => {
|
||||
// if (!!videoSource) {
|
||||
// this.log.d('Replacing video track ' + videoSource);
|
||||
// this.videoSource = videoSource;
|
||||
// }
|
||||
// if (!!audioSource) {
|
||||
// this.log.d('Replacing audio track ' + audioSource);
|
||||
// this.audioSource = audioSource;
|
||||
// }
|
||||
// this.destroyPublisher(this.participantService.getMyCameraPublisher());
|
||||
// const properties: PublisherProperties = {
|
||||
// videoSource: this.videoSource,
|
||||
// audioSource: this.audioSource,
|
||||
// publishVideo: this.participantService.hasCameraVideoActive(),
|
||||
// publishAudio: this.participantService.hasCameraAudioActive(),
|
||||
// mirror
|
||||
// };
|
||||
|
||||
const publisher = this.initPublisher(undefined, properties);
|
||||
this.participantService.setMyCameraPublisher(publisher);
|
||||
// const publisher = await this.initPublisher(undefined, properties);
|
||||
// this.participantService.setMyCameraPublisher(publisher);
|
||||
|
||||
publisher.once('streamPlaying', () => {
|
||||
this.participantService.setMyCameraPublisher(publisher);
|
||||
resolve();
|
||||
});
|
||||
// publisher.once('streamPlaying', () => {
|
||||
// this.participantService.setMyCameraPublisher(publisher);
|
||||
// resolve();
|
||||
// });
|
||||
|
||||
publisher.once('accessDenied', () => {
|
||||
reject();
|
||||
});
|
||||
});
|
||||
}
|
||||
// publisher.once('accessDenied', () => {
|
||||
// reject();
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
|
||||
sendSignal(type: Signal, connections?: Connection[], data?: any): void {
|
||||
const signalOptions: SignalOptions = {
|
||||
|
@ -282,28 +269,38 @@ export class OpenViduService {
|
|||
}
|
||||
}
|
||||
|
||||
async replaceTrack(currentPublisher: Publisher, newProperties: PublisherProperties) {
|
||||
async replaceTrack(videoType: VideoType, props: PublisherProperties) {
|
||||
try {
|
||||
if (!!currentPublisher) {
|
||||
if (currentPublisher === this.participantService.getMyCameraPublisher()) {
|
||||
// This branch has been disabled because echo problems replacing audio track.
|
||||
// this.stopAudioTracks(this.webcamMediaStream);
|
||||
// this.stopVideoTracks(this.webcamMediaStream);
|
||||
// this.webcamMediaStream = await this.OV.getUserMedia(newProperties);
|
||||
// const videoTrack: MediaStreamTrack = this.webcamMediaStream.getVideoTracks()[0];
|
||||
// const audioTrack: MediaStreamTrack = this.webcamMediaStream.getAudioTracks()[0];
|
||||
// if(!!videoTrack){
|
||||
// await this.participantService.getMyCameraPublisher().replaceTrack(videoTrack);
|
||||
// }
|
||||
// if(!!audioTrack) {
|
||||
// await this.participantService.getMyCameraPublisher().replaceTrack(audioTrack);
|
||||
// }
|
||||
} else if (currentPublisher === this.participantService.getMyScreenPublisher()) {
|
||||
const newScreenMediaStream = await this.OVScreen.getUserMedia(newProperties);
|
||||
this.stopTracks(this.screenMediaStream);
|
||||
await this.participantService.getMyScreenPublisher().replaceTrack(newScreenMediaStream.getVideoTracks()[0]);
|
||||
this.screenMediaStream = newScreenMediaStream;
|
||||
this.log.d(`Replacing ${videoType} track`, props);
|
||||
if (videoType === VideoType.CAMERA) {
|
||||
const isReplacingAudio = !!props.audioSource;
|
||||
const isReplacingVideo = !!props.videoSource;
|
||||
|
||||
if (this.platformService.isFirefox()) {
|
||||
// Firefox throw an exception trying to get a new MediaStreamTrack if the older one is not stopped
|
||||
// NotReadableError: Concurrent mic process limit. Stopping tracks before call to getUserMedia
|
||||
if (isReplacingVideo) {
|
||||
this.participantService.getMyCameraPublisher().stream.getMediaStream().getVideoTracks()[0].stop();
|
||||
} else if (isReplacingAudio) {
|
||||
this.participantService.getMyCameraPublisher().stream.getMediaStream().getAudioTracks()[0].stop();
|
||||
}
|
||||
}
|
||||
|
||||
const track = await this.OV.getUserMedia(props);
|
||||
if (isReplacingAudio) {
|
||||
// Replace audio track
|
||||
const audioTrack: MediaStreamTrack = track.getAudioTracks()[0];
|
||||
await this.participantService.getMyCameraPublisher().replaceTrack(audioTrack);
|
||||
} else if (isReplacingVideo) {
|
||||
// Replace video track
|
||||
const videoTrack: MediaStreamTrack = track.getVideoTracks()[0];
|
||||
await this.participantService.getMyCameraPublisher().replaceTrack(videoTrack);
|
||||
}
|
||||
} else if (videoType === VideoType.SCREEN) {
|
||||
const newScreenMediaStream = await this.OVScreen.getUserMedia(props);
|
||||
// this.stopTracks(this.screenMediaStream);
|
||||
// this.screenMediaStream = newScreenMediaStream;
|
||||
await this.participantService.getMyScreenPublisher().replaceTrack(newScreenMediaStream.getVideoTracks()[0]);
|
||||
}
|
||||
} catch (error) {
|
||||
this.log.e('Error replacing track ', error);
|
||||
|
@ -331,11 +328,25 @@ export class OpenViduService {
|
|||
return remoteCameraConnections;
|
||||
}
|
||||
|
||||
private stopTracks(mediaStream: MediaStream) {
|
||||
if (mediaStream) {
|
||||
mediaStream?.getAudioTracks().forEach((track) => track.stop());
|
||||
mediaStream?.getVideoTracks().forEach((track) => track.stop());
|
||||
// this.webcamMediaStream?.getAudioTracks().forEach((track) => track.stop());
|
||||
private disconnectSession(session: Session) {
|
||||
if (session) {
|
||||
if (session.sessionId === this.webcamSession?.sessionId) {
|
||||
this.log.d('Disconnecting webcam session');
|
||||
this.webcamSession?.disconnect();
|
||||
this.webcamSession = null;
|
||||
} else if (session.sessionId === this.screenSession?.sessionId) {
|
||||
this.log.d('Disconnecting screen session');
|
||||
this.screenSession?.disconnect();
|
||||
this.screenSession = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// private stopTracks(mediaStream: MediaStream) {
|
||||
// if (mediaStream) {
|
||||
// mediaStream?.getAudioTracks().forEach((track) => track.stop());
|
||||
// mediaStream?.getVideoTracks().forEach((track) => track.stop());
|
||||
// // this.webcamMediaStream?.getAudioTracks().forEach((track) => track.stop());
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ export class ParticipantService {
|
|||
this._screensharing.next(false);
|
||||
}
|
||||
|
||||
updateUsersStatus() {
|
||||
updateParticipantMediaStatus() {
|
||||
this._cameraVideoActive.next(this.localParticipant.isCameraVideoActive());
|
||||
if (this.isMyCameraEnabled()) {
|
||||
this._cameraAudioActive.next(this.localParticipant.isCameraAudioActive());
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { ILogger } from '../../models/logger.model';
|
||||
import { LoggerService } from '../logger/logger.service';
|
||||
import { Storage } from '../../models/storage.model';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
@ -13,12 +14,49 @@ export class StorageService {
|
|||
this.log = this.loggerSrv.get('StorageService');
|
||||
}
|
||||
|
||||
public set(key: string, item: any) {
|
||||
getNickname(): string {
|
||||
return this.get(Storage.USER_NICKNAME);
|
||||
}
|
||||
|
||||
setNickname(name: string){
|
||||
this.set(Storage.USER_NICKNAME, name);
|
||||
}
|
||||
getVideoDevice() {
|
||||
return this.get(Storage.VIDEO_DEVICE);
|
||||
}
|
||||
|
||||
setVideoDevice(device: any) {
|
||||
this.set(Storage.VIDEO_DEVICE, device);
|
||||
}
|
||||
|
||||
getAudioDevice() {
|
||||
return this.get(Storage.AUDIO_DEVICE);
|
||||
}
|
||||
|
||||
setAudioDevice(device: any) {
|
||||
this.set(Storage.AUDIO_DEVICE, device);
|
||||
}
|
||||
isVideoMuted(): boolean {
|
||||
return this.get(Storage.VIDEO_MUTED) === 'true';
|
||||
}
|
||||
setVideoMuted(muted: boolean) {
|
||||
this.set(Storage.VIDEO_MUTED, `${muted}`);
|
||||
}
|
||||
|
||||
isAudioMuted(): boolean {
|
||||
return this.get(Storage.AUDIO_MUTED) === 'true';
|
||||
}
|
||||
|
||||
setAudioMuted(muted: boolean) {
|
||||
this.set(Storage.AUDIO_MUTED, `${muted}`);
|
||||
}
|
||||
|
||||
private set(key: string, item: any) {
|
||||
const value = JSON.stringify({ item: item });
|
||||
// this.log.d('Storing on localStorage "' + key + '" with value "' + value + '"');
|
||||
this.storage.setItem(key, value);
|
||||
}
|
||||
public get(key: string): any {
|
||||
private get(key: string): any {
|
||||
const value = JSON.parse(this.storage.getItem(key));
|
||||
return value?.item ? value.item : null;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue