diff --git a/openvidu-testapp/src/app/components/video-track/video-track.component.css b/openvidu-testapp/src/app/components/video-track/video-track.component.css index 81a5faadc..b16e3f017 100644 --- a/openvidu-testapp/src/app/components/video-track/video-track.component.css +++ b/openvidu-testapp/src/app/components/video-track/video-track.component.css @@ -56,18 +56,31 @@ video { /* Keep the form-field visually compact (16×16 clipped box). The CDK overlay uses the Popover API (top layer) so it is immune to overflow:hidden and renders at its natural size. */ -#max-video-quality { +#max-video-quality, +#restart-video-resolution { width: 16px; height: 16px; overflow: hidden; font-size: 10px; font-weight: bold; + --mat-form-field-container-vertical-padding: 0px; } -::ng-deep #max-video-quality .mdc-notched-outline * { +/* The MDC outlined text field reserves 16px of horizontal padding + for the value, which alone exceeds this 16px-wide box and pushes + the value/arrow trigger (and therefore the dropdown svg) out of + the visible area. Removing it keeps the trigger inside the clip. */ +::ng-deep #max-video-quality .mat-mdc-text-field-wrapper, +::ng-deep #restart-video-resolution .mat-mdc-text-field-wrapper { + padding: 0; +} + +::ng-deep #max-video-quality .mdc-notched-outline *, +::ng-deep #restart-video-resolution .mdc-notched-outline * { border-color: transparent !important; } -::ng-deep #max-video-quality .mat-mdc-form-field-subscript-wrapper { +::ng-deep #max-video-quality .mat-mdc-form-field-subscript-wrapper, +::ng-deep #restart-video-resolution .mat-mdc-form-field-subscript-wrapper { display: none !important; } diff --git a/openvidu-testapp/src/app/components/video-track/video-track.component.html b/openvidu-testapp/src/app/components/video-track/video-track.component.html index 5cd416bea..401aced44 100644 --- a/openvidu-testapp/src/app/components/video-track/video-track.component.html +++ b/openvidu-testapp/src/app/components/video-track/video-track.component.html @@ -7,20 +7,26 @@ - } - @if (localParticipant) { + - } - @if (localParticipant) { + + + + + @for (r of ['1920x1080', '1280x720', '640x360', '320x180']; track r) { + {{r}} + } + + } @if (!localParticipant) { - } - @if (!localParticipant) { + - } - @if (!localParticipant) { + @for (q of ['LOW', 'MEDIUM', 'HIGH']; track q) { diff --git a/openvidu-testapp/src/app/components/video-track/video-track.component.ts b/openvidu-testapp/src/app/components/video-track/video-track.component.ts index 27b9b3ca6..a5448aefc 100644 --- a/openvidu-testapp/src/app/components/video-track/video-track.component.ts +++ b/openvidu-testapp/src/app/components/video-track/video-track.component.ts @@ -2,6 +2,7 @@ import { Component, inject, ChangeDetectionStrategy } from '@angular/core'; import { NgClass } from '@angular/common'; import { LocalTrack, + LocalVideoTrack, VideoTrack, RemoteTrackPublication, VideoQuality, @@ -32,6 +33,8 @@ import { MatSelectModule } from '@angular/material/select'; export class VideoTrackComponent extends TrackComponent { muteVideoIcon: string = 'videocam'; maxVideoQuality: string; + // Resolution to re-capture the local video track at (see onRestartResolutionChange) + restartResolution: string; videoZoom = false; @@ -96,6 +99,16 @@ export class VideoTrackComponent extends TrackComponent { ); } + // Re-captures the local video track at the selected resolution. Useful to make + // the encoder change its layer structure on the fly: an SVC encoder drops its + // upper spatial layers when the capture is too small to host them + async onRestartResolutionChange() { + const [width, height] = this.restartResolution.split('x').map(Number); + await (this._track as LocalVideoTrack).restartTrack({ + resolution: { width, height, frameRate: 30 }, + }); + } + openInfoDialog() { const updateFunction = async (): Promise => { const videoLayers: any[] = [];