mirror of https://github.com/OpenVidu/openvidu.git
openvidu-components: Added network control directives
Allowed frameRate, resolution and simulcast customizationpull/816/head
parent
6bf48078a5
commit
9a6a4cbf25
|
@ -30,6 +30,8 @@ import { StorageService } from '../../services/storage/storage.service';
|
|||
* | **displayParticipantName** | `boolean` | {@link StreamDisplayParticipantNameDirective} |
|
||||
* | **displayAudioDetection** | `boolean` | {@link StreamDisplayAudioDetectionDirective} |
|
||||
* | **settingsButton** | `boolean` | {@link StreamSettingsButtonDirective} |
|
||||
* | **resolution** | `string` | {@link StreamResolutionDirective} |
|
||||
* | **frameRate** | `number` | {@link StreamFrameRateDirective} |
|
||||
*
|
||||
* <p class="component-link-text">
|
||||
* <span class="italic">See all {@link ApiDirectiveModule API Directives}</span>
|
||||
|
@ -60,7 +62,7 @@ import { StorageService } from '../../services/storage/storage.service';
|
|||
animations: [
|
||||
trigger('posterAnimation', [
|
||||
transition(':enter', [style({ opacity: 0 }), animate('100ms', style({ opacity: 1 }))]),
|
||||
transition(':leave', [style({ opacity: 1 }), animate('200ms', style({ opacity: 0 }))]),
|
||||
transition(':leave', [style({ opacity: 1 }), animate('200ms', style({ opacity: 0 }))])
|
||||
])
|
||||
]
|
||||
})
|
||||
|
@ -140,6 +142,7 @@ export class StreamComponent implements OnInit {
|
|||
if (this._stream.participant) {
|
||||
this.nickname = this._stream.participant.nickname;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -174,6 +177,12 @@ export class StreamComponent implements OnInit {
|
|||
this.subscribeToStreamDirectives();
|
||||
}
|
||||
|
||||
async ngAfterViewInit() {
|
||||
if (this._stream.streamManager) {
|
||||
await this.openviduService.updateVideoEncodingParameters(this._stream.streamManager);
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.cdkSrv.setSelector('body');
|
||||
if (this.settingsButtonSub) this.settingsButtonSub.unsubscribe();
|
||||
|
@ -214,7 +223,7 @@ export class StreamComponent implements OnInit {
|
|||
* @ignore
|
||||
*/
|
||||
toggleMuteForcibly() {
|
||||
if(this._stream.participant){
|
||||
if (this._stream.participant) {
|
||||
this.participantService.setRemoteMutedForcibly(this._stream.participant.id, !this._stream.participant.isMutedForcibly);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@ import { LangOption } from '../../models/lang.model';
|
|||
* | **participantName** | `string` | {@link ParticipantNameDirective} |
|
||||
* | **videoMuted** | `boolean` | {@link VideoMutedDirective} |
|
||||
* | **audioMuted** | `boolean` | {@link AudioMutedDirective} |
|
||||
| **simulcast** | `boolean` | {@link SimulcastDirective} |
|
||||
* | **toolbarScreenshareButton** | `boolean` | {@link ToolbarScreenshareButtonDirective} |
|
||||
* | **toolbarFullscreenButton** | `boolean` | {@link ToolbarFullscreenButtonDirective} |
|
||||
* | **toolbarCaptionsButton** | `boolean` | {@link ToolbarCaptionsButtonDirective} |
|
||||
|
@ -75,6 +76,8 @@ import { LangOption } from '../../models/lang.model';
|
|||
* | **streamDisplayParticipantName** | `boolean` | {@link StreamDisplayParticipantNameDirective} |
|
||||
* | **streamDisplayAudioDetection** | `boolean` | {@link StreamDisplayAudioDetectionDirective} |
|
||||
* | **streamSettingsButton** | `boolean` | {@link StreamSettingsButtonDirective} |
|
||||
* | **streamFrameRate** | `number` | {@link StreamFrameRateDirective} |
|
||||
* | **streamResolution** | `string` | {@link StreamResolutionDirective} |
|
||||
* | **participantPanelItemMuteButton** | `boolean` | {@link ParticipantPanelItemMuteButtonDirective} |
|
||||
* | **recordingActivityRecordingList** | `{@link RecordingInfo}[]` | {@link RecordingActivityRecordingsListDirective} |
|
||||
* | **recordingActivityRecordingError** | `any` | {@link RecordingActivityRecordingErrorDirective} |
|
||||
|
@ -603,7 +606,12 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
|
|||
private async initwebcamPublisher(): Promise<void> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const publisher = await this.openviduService.initDefaultPublisher();
|
||||
const pp = {
|
||||
resolution: this.libService.getStreamResolution(),
|
||||
frameRate: this.libService.getStreamFrameRate(),
|
||||
videoSimulcast: this.libService.isSimulcastEnabled()
|
||||
};
|
||||
const publisher = await this.openviduService.initDefaultPublisher(pp);
|
||||
|
||||
if (publisher) {
|
||||
publisher.once('accessDenied', async (e: any) => {
|
||||
|
|
|
@ -8,7 +8,9 @@ import { RecordingActivityRecordingErrorDirective, RecordingActivityRecordingsLi
|
|||
import {
|
||||
StreamDisplayAudioDetectionDirective,
|
||||
StreamDisplayParticipantNameDirective,
|
||||
StreamSettingsButtonDirective
|
||||
StreamSettingsButtonDirective,
|
||||
StreamFrameRateDirective,
|
||||
StreamResolutionDirective
|
||||
} from './stream.directive';
|
||||
import {
|
||||
ToolbarActivitiesPanelButtonDirective,
|
||||
|
@ -32,7 +34,8 @@ import {
|
|||
MinimalDirective,
|
||||
ParticipantNameDirective,
|
||||
PrejoinDirective,
|
||||
VideoMutedDirective
|
||||
VideoMutedDirective,
|
||||
SimulcastDirective
|
||||
} from './videoconference.directive';
|
||||
|
||||
@NgModule({
|
||||
|
@ -44,6 +47,7 @@ import {
|
|||
CaptionsLangDirective,
|
||||
PrejoinDirective,
|
||||
VideoMutedDirective,
|
||||
SimulcastDirective,
|
||||
AudioMutedDirective,
|
||||
ToolbarScreenshareButtonDirective,
|
||||
ToolbarFullscreenButtonDirective,
|
||||
|
@ -61,6 +65,8 @@ import {
|
|||
StreamDisplayParticipantNameDirective,
|
||||
StreamDisplayAudioDetectionDirective,
|
||||
StreamSettingsButtonDirective,
|
||||
StreamFrameRateDirective,
|
||||
StreamResolutionDirective,
|
||||
LogoDirective,
|
||||
ParticipantPanelItemMuteButtonDirective,
|
||||
ParticipantNameDirective,
|
||||
|
@ -80,6 +86,7 @@ import {
|
|||
CaptionsLangDirective,
|
||||
PrejoinDirective,
|
||||
VideoMutedDirective,
|
||||
SimulcastDirective,
|
||||
AudioMutedDirective,
|
||||
ToolbarScreenshareButtonDirective,
|
||||
ToolbarFullscreenButtonDirective,
|
||||
|
@ -97,6 +104,8 @@ import {
|
|||
StreamDisplayParticipantNameDirective,
|
||||
StreamDisplayAudioDetectionDirective,
|
||||
StreamSettingsButtonDirective,
|
||||
StreamFrameRateDirective,
|
||||
StreamResolutionDirective,
|
||||
LogoDirective,
|
||||
ParticipantPanelItemMuteButtonDirective,
|
||||
ParticipantNameDirective,
|
||||
|
|
|
@ -1,6 +1,108 @@
|
|||
import { AfterViewInit, Directive, ElementRef, Input, OnDestroy } from '@angular/core';
|
||||
import { OpenViduAngularConfigService } from '../../services/config/openvidu-angular.config.service';
|
||||
|
||||
|
||||
/**
|
||||
* The **frameRate** directive allows initialize the publisher with a specific frame rate in stream component.
|
||||
*
|
||||
* Default: `30`
|
||||
*
|
||||
* It can be used in the parent element {@link VideoconferenceComponent} specifying the name of the `stream` component:
|
||||
*
|
||||
* @example
|
||||
* <ov-videoconference [streamFrameRate]="10"></ov-videoconference>
|
||||
*
|
||||
* \
|
||||
* And it also can be used in the {@link StreamComponent}.
|
||||
* @example
|
||||
* <ov-stream [frameRate]="10"></ov-stream>
|
||||
*/
|
||||
@Directive({
|
||||
selector: 'ov-videoconference[streamFrameRate], ov-stream[frameRate]'
|
||||
})
|
||||
export class StreamFrameRateDirective implements AfterViewInit, OnDestroy {
|
||||
@Input() set streamFrameRate(value: number) {
|
||||
this._frameRate = value;
|
||||
this.update(this._frameRate);
|
||||
}
|
||||
@Input() set frameRate(value: number) {
|
||||
this._frameRate = value;
|
||||
this.update(this._frameRate);
|
||||
}
|
||||
|
||||
_frameRate: number;
|
||||
|
||||
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.clear();
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.update(this._frameRate);
|
||||
}
|
||||
|
||||
update(value: number) {
|
||||
if (this.libService.streamFrameRate.getValue() !== value) {
|
||||
this.libService.streamFrameRate.next(value);
|
||||
}
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.update(30);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The **resolution** directive allows to set a specific participant resolution in stream component.
|
||||
*
|
||||
* Default: `640x480`
|
||||
*
|
||||
* It can be used in the parent element {@link VideoconferenceComponent} specifying the name of the `stream` component:
|
||||
*
|
||||
* @example
|
||||
* <ov-videoconference [streamResolution]="'320x240'"></ov-videoconference>
|
||||
*
|
||||
* \
|
||||
* And it also can be used in the {@link StreamComponent}.
|
||||
* @example
|
||||
* <ov-stream [resolution]="'320x240'"></ov-stream>
|
||||
*/
|
||||
@Directive({
|
||||
selector: 'ov-videoconference[streamResolution], ov-stream[resolution]'
|
||||
})
|
||||
export class StreamResolutionDirective implements AfterViewInit, OnDestroy {
|
||||
@Input() set streamResolution(value: string) {
|
||||
this._resolution = value;
|
||||
this.update(this._resolution);
|
||||
}
|
||||
@Input() set resolution(value: string) {
|
||||
this._resolution = value;
|
||||
this.update(this._resolution);
|
||||
}
|
||||
|
||||
_resolution: string;
|
||||
|
||||
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.clear();
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.update(this._resolution);
|
||||
}
|
||||
|
||||
update(value: string) {
|
||||
if (this.libService.streamResolution.getValue() !== value) {
|
||||
this.libService.streamResolution.next(value);
|
||||
}
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.update('640x480');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* The **displayParticipantName** directive allows show/hide the participants name in stream component.
|
||||
*
|
||||
|
|
|
@ -5,7 +5,6 @@ import { OpenViduAngularConfigService } from '../../services/config/openvidu-ang
|
|||
import { TranslateService } from '../../services/translate/translate.service';
|
||||
import { LangOption } from '../../models/lang.model';
|
||||
|
||||
|
||||
/**
|
||||
* The **minimal** directive applies a minimal UI hiding all controls except for cam and mic.
|
||||
*
|
||||
|
@ -79,7 +78,7 @@ export class MinimalDirective implements OnDestroy {
|
|||
* @example
|
||||
* <ov-videoconference [lang]="'es'"></ov-videoconference>
|
||||
*/
|
||||
@Directive({
|
||||
@Directive({
|
||||
selector: 'ov-videoconference[lang]'
|
||||
})
|
||||
export class LangDirective implements OnDestroy {
|
||||
|
@ -152,7 +151,7 @@ export class LangOptionsDirective implements OnDestroy {
|
|||
/**
|
||||
* @ignore
|
||||
*/
|
||||
@Input() set langOptions(value: LangOption []) {
|
||||
@Input() set langOptions(value: LangOption[]) {
|
||||
this.update(value);
|
||||
}
|
||||
|
||||
|
@ -178,7 +177,7 @@ export class LangOptionsDirective implements OnDestroy {
|
|||
/**
|
||||
* @ignore
|
||||
*/
|
||||
update(value: LangOption [] | undefined) {
|
||||
update(value: LangOption[] | undefined) {
|
||||
this.translateService.setLanguageOptions(value);
|
||||
}
|
||||
}
|
||||
|
@ -208,7 +207,7 @@ export class LangOptionsDirective implements OnDestroy {
|
|||
* @example
|
||||
* <ov-videoconference [captionsLang]="'es-ES'"></ov-videoconference>
|
||||
*/
|
||||
@Directive({
|
||||
@Directive({
|
||||
selector: 'ov-videoconference[captionsLang]'
|
||||
})
|
||||
export class CaptionsLangDirective implements OnDestroy {
|
||||
|
@ -269,14 +268,14 @@ export class CaptionsLangDirective implements OnDestroy {
|
|||
* @example
|
||||
* <ov-videoconference [captionsLangOptions]="[{name:'Spanish', lang: 'es-ES'}]"></ov-videoconference>
|
||||
*/
|
||||
@Directive({
|
||||
@Directive({
|
||||
selector: 'ov-videoconference[captionsLangOptions]'
|
||||
})
|
||||
export class CaptionsLangOptionsDirective implements OnDestroy {
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
@Input() set captionsLangOptions(value: CaptionsLangOption []) {
|
||||
@Input() set captionsLangOptions(value: CaptionsLangOption[]) {
|
||||
this.update(value);
|
||||
}
|
||||
|
||||
|
@ -302,12 +301,11 @@ export class CaptionsLangOptionsDirective implements OnDestroy {
|
|||
/**
|
||||
* @ignore
|
||||
*/
|
||||
update(value: CaptionsLangOption [] | undefined) {
|
||||
update(value: CaptionsLangOption[] | undefined) {
|
||||
this.captionService.setLanguageOptions(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The **participantName** directive sets the participant name. It can be useful for aplications which doesn't need the prejoin page.
|
||||
*
|
||||
|
@ -477,7 +475,6 @@ export class VideoMutedDirective implements OnDestroy {
|
|||
selector: 'ov-videoconference[audioMuted]'
|
||||
})
|
||||
export class AudioMutedDirective implements OnDestroy {
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
|
@ -510,3 +507,56 @@ export class AudioMutedDirective implements OnDestroy {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The **simulcast** directive allows to enable/disable the Simulcast feature. Simulcast is a technique that allows
|
||||
* to send multiple versions of the same video stream at different resolutions, framerates and qualities. This way,
|
||||
* the receiver can subscribe to the most appropriate stream for its current network conditions.
|
||||
*
|
||||
* It is only available for {@link VideoconferenceComponent} and **only if OpenVidu Server was configured to use the
|
||||
* mediasoup media server**. Otherwise, Simulcast will be disabled.
|
||||
*
|
||||
* Default: `false`
|
||||
*
|
||||
* @example
|
||||
* <ov-videoconference [simulcast]="true"></ov-videoconference>
|
||||
*/
|
||||
@Directive({
|
||||
selector: 'ov-videoconference[simulcast]'
|
||||
})
|
||||
export class SimulcastDirective implements OnDestroy {
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
@Input() set simulcast(value: boolean) {
|
||||
this.update(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
constructor(public elementRef: ElementRef, private libService: OpenViduAngularConfigService) {}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
clear() {
|
||||
this.update(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
update(value: boolean) {
|
||||
if (this.libService.simulcast.getValue() !== value) {
|
||||
this.libService.simulcast.next(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,9 @@ export class OpenViduAngularConfigService {
|
|||
prejoin = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||
prejoinObs: Observable<boolean>;
|
||||
|
||||
simulcast = <BehaviorSubject<boolean>>new BehaviorSubject(false);
|
||||
simulcastObs: Observable<boolean>;
|
||||
|
||||
videoMuted = <BehaviorSubject<boolean | undefined>>new BehaviorSubject(undefined);
|
||||
videoMutedObs: Observable<boolean | undefined>;
|
||||
audioMuted = <BehaviorSubject<boolean | undefined>>new BehaviorSubject(undefined);
|
||||
|
@ -50,6 +53,11 @@ export class OpenViduAngularConfigService {
|
|||
displaySessionName = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||
displaySessionNameObs: Observable<boolean>;
|
||||
|
||||
streamFrameRate = <BehaviorSubject<number>>new BehaviorSubject(30);
|
||||
streamFrameRateObs: Observable<number>;
|
||||
|
||||
streamResolution = <BehaviorSubject<string>>new BehaviorSubject('640x480');
|
||||
streamResolutionObs: Observable<string>;
|
||||
displayLogo = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||
displayLogoObs: Observable<boolean>;
|
||||
displayParticipantName = <BehaviorSubject<boolean>>new BehaviorSubject(true);
|
||||
|
@ -91,6 +99,7 @@ export class OpenViduAngularConfigService {
|
|||
this.prejoinObs = this.prejoin.asObservable();
|
||||
this.videoMutedObs = this.videoMuted.asObservable();
|
||||
this.audioMutedObs = this.audioMuted.asObservable();
|
||||
this.simulcastObs = this.simulcast.asObservable();
|
||||
//Toolbar observables
|
||||
this.screenshareButtonObs = this.screenshareButton.asObservable();
|
||||
this.fullscreenButtonObs = this.fullscreenButton.asObservable();
|
||||
|
@ -106,6 +115,8 @@ export class OpenViduAngularConfigService {
|
|||
this.toolbarSettingsButtonObs = this.toolbarSettingsButton.asObservable();
|
||||
this.captionsButtonObs = this.captionsButton.asObservable();
|
||||
//Stream observables
|
||||
this.streamFrameRateObs = this.streamFrameRate.asObservable();
|
||||
this.streamResolutionObs = this.streamResolution.asObservable();
|
||||
this.displayParticipantNameObs = this.displayParticipantName.asObservable();
|
||||
this.displayAudioDetectionObs = this.displayAudioDetection.asObservable();
|
||||
this.streamSettingsButtonObs = this.streamSettingsButton.asObservable();
|
||||
|
@ -145,4 +156,16 @@ export class OpenViduAngularConfigService {
|
|||
isBroadcastingEnabled(): boolean {
|
||||
return this.broadcastingButton.getValue() && this.broadcastingActivity.getValue();
|
||||
}
|
||||
|
||||
getStreamResolution(): string {
|
||||
return this.streamResolution.getValue();
|
||||
}
|
||||
|
||||
getStreamFrameRate(): number {
|
||||
return this.streamFrameRate.getValue();
|
||||
}
|
||||
|
||||
isSimulcastEnabled(): boolean {
|
||||
return this.simulcast.getValue() || false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,8 @@ import {
|
|||
PublisherProperties,
|
||||
Session,
|
||||
SignalOptions,
|
||||
Stream
|
||||
Stream,
|
||||
StreamManager
|
||||
} from 'openvidu-browser';
|
||||
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
|
@ -49,7 +50,7 @@ export class OpenViduService {
|
|||
* @internal
|
||||
*/
|
||||
constructor(
|
||||
protected openviduAngularConfigSrv: OpenViduAngularConfigService,
|
||||
protected libService: OpenViduAngularConfigService,
|
||||
protected platformService: PlatformService,
|
||||
protected loggerSrv: LoggerService,
|
||||
private injector: Injector,
|
||||
|
@ -69,13 +70,13 @@ export class OpenViduService {
|
|||
interval: 50
|
||||
}
|
||||
});
|
||||
if (this.openviduAngularConfigSrv.isProduction()) this.OV.enableProdMode();
|
||||
if (this.libService.isProduction()) this.OV.enableProdMode();
|
||||
this.webcamSession = this.OV.initSession();
|
||||
|
||||
// Initialize screen session only if it is not mobile platform
|
||||
if (!this.platformService.isMobile()) {
|
||||
this.OVScreen = new OpenVidu();
|
||||
if (this.openviduAngularConfigSrv.isProduction()) this.OVScreen.enableProdMode();
|
||||
if (this.libService.isProduction()) this.OVScreen.enableProdMode();
|
||||
this.screenSession = this.OVScreen.initSession();
|
||||
}
|
||||
}
|
||||
|
@ -244,11 +245,34 @@ export class OpenViduService {
|
|||
this.disconnectSession(this.screenSession);
|
||||
}
|
||||
|
||||
async updateVideoEncodingParameters(streamManager: StreamManager) {
|
||||
if (!streamManager) return;
|
||||
const track = streamManager?.stream.getMediaStream().getVideoTracks()[0];
|
||||
const videoSender = streamManager?.stream
|
||||
.getRTCPeerConnection()
|
||||
.getSenders()
|
||||
.find((sender) => sender.track === track);
|
||||
|
||||
if (!videoSender) return;
|
||||
|
||||
const parameters: RTCRtpSendParameters = videoSender.getParameters();
|
||||
const desiredFrameRate = this.libService.getStreamFrameRate();
|
||||
const desiredWidth = Number(this.libService.getStreamResolution().split('x')[0]);
|
||||
const desiredResolution = Number(track?.getConstraints()?.width) / desiredWidth ?? 1.0;
|
||||
parameters.encodings.forEach((encoding: RTCRtpEncodingParameters) => {
|
||||
if (desiredFrameRate > 0 && encoding['maxFramerate'] !== desiredFrameRate) encoding['maxFramerate'] = desiredFrameRate;
|
||||
if (desiredResolution >= 1 && encoding['scaleResolutionDownBy'] !== desiredResolution) {
|
||||
encoding['scaleResolutionDownBy'] = desiredResolution;
|
||||
}
|
||||
});
|
||||
await videoSender.setParameters(parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Initialize a publisher checking devices saved on storage or if participant have devices available.
|
||||
*/
|
||||
async initDefaultPublisher(): Promise<Publisher | undefined> {
|
||||
async initDefaultPublisher(pp?: Partial<PublisherProperties>): Promise<Publisher | undefined> {
|
||||
const hasVideoDevices = this.deviceService.hasVideoDeviceAvailable();
|
||||
const hasAudioDevices = this.deviceService.hasAudioDeviceAvailable();
|
||||
const isVideoActive = !this.deviceService.isVideoMuted();
|
||||
|
@ -259,7 +283,7 @@ export class OpenViduService {
|
|||
|
||||
if (hasVideoDevices) {
|
||||
// Video is active, assign the device selected
|
||||
videoSource = this.deviceService.getCameraSelected().device;
|
||||
videoSource = this.deviceService.getCameraSelected()?.device ?? false;
|
||||
} else if (!isVideoActive && hasVideoDevices) {
|
||||
// Video is muted, assign the default device
|
||||
// videoSource = undefined;
|
||||
|
@ -267,18 +291,21 @@ export class OpenViduService {
|
|||
|
||||
if (hasAudioDevices) {
|
||||
// Audio is active, assign the device selected
|
||||
audioSource = this.deviceService.getMicrophoneSelected().device;
|
||||
audioSource = this.deviceService.getMicrophoneSelected()?.device ?? false;
|
||||
} else if (!isAudioActive && hasAudioDevices) {
|
||||
// Audio is muted, assign the default device
|
||||
// audioSource = undefined;
|
||||
}
|
||||
|
||||
const mirror = this.deviceService.getCameraSelected() && this.deviceService.getCameraSelected().type === CameraType.FRONT;
|
||||
const mirror = this.deviceService.getCameraSelected() && this.deviceService.getCameraSelected()?.type === CameraType.FRONT;
|
||||
const properties: PublisherProperties = {
|
||||
videoSource,
|
||||
audioSource,
|
||||
publishVideo: isVideoActive,
|
||||
publishAudio: isAudioActive,
|
||||
resolution: pp?.resolution ?? '640x480',
|
||||
frameRate: pp?.frameRate ?? 30,
|
||||
videoSimulcast: pp?.videoSimulcast ?? false,
|
||||
mirror
|
||||
};
|
||||
if (hasVideoDevices || hasAudioDevices) {
|
||||
|
@ -520,7 +547,6 @@ export class OpenViduService {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param pp {@link PublisherProperties}
|
||||
|
@ -538,7 +564,7 @@ export class OpenViduService {
|
|||
this.forceStopMediaTracks(participantService.getMyCameraPublisher().stream.getMediaStream(), trackType);
|
||||
return this.OV.getUserMedia(pp);
|
||||
} catch (error) {
|
||||
console.warn('Error creating MediaStream', error);
|
||||
this.log.w('Error creating MediaStream', error);
|
||||
if ((<OpenViduError>error).name === OpenViduErrorName.DEVICE_ACCESS_DENIED) {
|
||||
this.log.w('The device requested is not available. Restoring the older one');
|
||||
// The track requested is not available so we are getting the old tracks ids for recovering the track
|
||||
|
@ -559,7 +585,7 @@ export class OpenViduService {
|
|||
*/
|
||||
myNicknameHasBeenChanged(): boolean {
|
||||
const participantService = this.injector.get(ParticipantService);
|
||||
let oldNickname: string = "";
|
||||
let oldNickname: string = '';
|
||||
try {
|
||||
const connData = JSON.parse(this.cleanConnectionData(this.webcamSession.connection.data));
|
||||
oldNickname = connData.clientData;
|
||||
|
|
|
@ -1,11 +1,18 @@
|
|||
<ov-videoconference
|
||||
[simulcast]="true"
|
||||
[tokens]="tokens"
|
||||
[minimal]="false"
|
||||
[lang]="'es'"
|
||||
[langOptions]="[{ name: 'Spanish', lang: 'es' },{ name: 'custom', lang: 'cus' }]"
|
||||
[langOptions]="[
|
||||
{ name: 'Spanish', lang: 'es' },
|
||||
{ name: 'custom', lang: 'cus' }
|
||||
]"
|
||||
[captionsLang]=""
|
||||
[captionsLangOptions]="[{ name: 'Spanish', lang: 'es-ES' },{ name: 'English', lang: 'en-US' }]"
|
||||
[prejoin]="true"
|
||||
[captionsLangOptions]="[
|
||||
{ name: 'Spanish', lang: 'es-ES' },
|
||||
{ name: 'English', lang: 'en-US' }
|
||||
]"
|
||||
[prejoin]="false"
|
||||
[participantName]="'Participant'"
|
||||
[videoMuted]="false"
|
||||
[audioMuted]="false"
|
||||
|
@ -20,6 +27,8 @@
|
|||
[toolbarParticipantsPanelButton]="true"
|
||||
[toolbarDisplayLogo]="true"
|
||||
[toolbarDisplaySessionName]="true"
|
||||
[streamResolution]="'160x120'"
|
||||
[streamFrameRate]="2"
|
||||
[streamDisplayParticipantName]="true"
|
||||
[streamDisplayAudioDetection]="true"
|
||||
[streamSettingsButton]="true"
|
||||
|
@ -49,9 +58,12 @@
|
|||
(onNodeCrashed)="onNodeCrashed()"
|
||||
(onLangChanged)="onLangChanged($event)"
|
||||
>
|
||||
<!-- <div *ovActivitiesPanel>HELLO</div> -->
|
||||
<div *ovActivitiesPanel>{{ 'CUSTOM.BUTTON' | translate }}</div>
|
||||
|
||||
<!-- <ov-toolbar *ovToolbar [activitiesPanelButton]="false"
|
||||
[chatPanelButton]="false"></ov-toolbar> -->
|
||||
|
||||
<!-- <div *ovStream="let stream">
|
||||
<ov-stream [stream]="stream" [displayParticipantName]="false" [frameRate]="2" [resolution]="'160x120'"></ov-stream>
|
||||
<p>{{ stream.participant.nickname }}</p>
|
||||
</div> -->
|
||||
</ov-videoconference>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<ov-videoconference
|
||||
*ngIf="success"
|
||||
[simulcast]="_simulcast"
|
||||
[participantName]="_participantName"
|
||||
[tokens]="_tokens"
|
||||
[minimal]="_minimal"
|
||||
|
@ -26,6 +27,8 @@
|
|||
[streamDisplayParticipantName]="_streamDisplayParticipantName"
|
||||
[streamDisplayAudioDetection]="_streamDisplayAudioDetection"
|
||||
[streamSettingsButton]="_streamSettingsButton"
|
||||
[streamResolution]="_streamResolution"
|
||||
[streamFrameRate]="_streamFrameRate"
|
||||
[participantPanelItemMuteButton]="_participantPanelItemMuteButton"
|
||||
[activitiesPanelRecordingActivity]="_activitiesPanelRecordingActivity"
|
||||
[activitiesPanelBroadcastingActivity]="_activitiesPanelBroadcastingActivity"
|
||||
|
|
|
@ -60,6 +60,11 @@ export class OpenviduWebComponentComponent implements OnInit {
|
|||
* @internal
|
||||
*/
|
||||
_audioMuted: boolean = false;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_simulcast: boolean = false;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
@ -124,6 +129,14 @@ export class OpenviduWebComponentComponent implements OnInit {
|
|||
* @internal
|
||||
*/
|
||||
_streamSettingsButton: boolean = true;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_streamResolution: string = '640x480';
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_streamFrameRate: number = 30;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
@ -188,11 +201,11 @@ export class OpenviduWebComponentComponent implements OnInit {
|
|||
}
|
||||
|
||||
/**
|
||||
* The **langOptions** directive allows to set the application language options.
|
||||
* It will override the application languages provided by default.
|
||||
* This propety is an array of objects which must comply with the {@link LangOption} interface.
|
||||
*
|
||||
* It is only available for {@link VideoconferenceComponent}.
|
||||
* The **langOptions** directive allows to set the application language options.
|
||||
* It will override the application languages provided by default.
|
||||
* This propety is an array of objects which must comply with the {@link LangOption} interface.
|
||||
*
|
||||
* It is only available for {@link VideoconferenceComponent}.
|
||||
*
|
||||
* Default: ```
|
||||
* [
|
||||
|
@ -209,7 +222,7 @@ export class OpenviduWebComponentComponent implements OnInit {
|
|||
* ]```
|
||||
*
|
||||
* Note: If you want to add a new language, you must add a new object with the name and the language code (e.g. `{ name: 'Custom', lang: 'cus' }`)
|
||||
* and then add the language file in the `assets/lang` folder with the name `cus.json`.
|
||||
* and then add the language file in the `assets/lang` folder with the name `cus.json`.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
|
@ -295,6 +308,20 @@ export class OpenviduWebComponentComponent implements OnInit {
|
|||
this._audioMuted = this.castToBoolean(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The **simulcast** directive allows to enable/disable the Simulcast feature. Simulcast is a technique that allows
|
||||
* to send multiple versions of the same video stream at different resolutions, framerates and qualities. This way,
|
||||
* the receiver can subscribe to the most appropriate stream for its current network conditions.
|
||||
*
|
||||
* Default: `false`
|
||||
*
|
||||
* @example
|
||||
* <openvidu-webcomponent simulcast="true"></openvidu-webcomponent>
|
||||
*/
|
||||
@Input() set simulcast(value: string | boolean) {
|
||||
this._simulcast = this.castToBoolean(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The **toolbarScreenshareButton** attribute allows show/hide the screenshare toolbar button.
|
||||
*
|
||||
|
@ -524,6 +551,36 @@ export class OpenviduWebComponentComponent implements OnInit {
|
|||
@Input() set streamSettingsButton(value: string | boolean) {
|
||||
this._streamSettingsButton = this.castToBoolean(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The **resolution** directive allows to set a specific participant resolution in stream component.
|
||||
*
|
||||
* Default: `640x480`
|
||||
*
|
||||
* <div class="warn-container">
|
||||
* <span>WARNING</span>: If you want to use this parameter to OpenVidu Web Component statically, you have to replace the <strong>camelCase</strong> with a <strong>hyphen between words</strong>.</div>
|
||||
*
|
||||
* @example
|
||||
* <openvidu-webcomponent stream-resolution="'320x240'"></openvidu-webcomponent>
|
||||
*/
|
||||
@Input() set streamResolution(value: string) {
|
||||
this._streamResolution = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The **frameRate** directive allows initialize the publisher with a specific frame rate in stream component.
|
||||
*
|
||||
* Default: `30`
|
||||
*
|
||||
* <div class="warn-container">
|
||||
* <span>WARNING</span>: If you want to use this parameter to OpenVidu Web Component statically, you have to replace the <strong>camelCase</strong> with a <strong>hyphen between words</strong>.</div>
|
||||
*
|
||||
* @example
|
||||
* <openvidu-webcomponent stream-frame-rate="30"></openvidu-webcomponent>
|
||||
*/
|
||||
@Input() set streamFrameRate(value: number) {
|
||||
this._streamFrameRate = Number(value);
|
||||
}
|
||||
/**
|
||||
* The **participantPanelItemMuteButton** attribute allows show/hide the muted button in participant panel item component.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue