ngx-videogular icon indicating copy to clipboard operation
ngx-videogular copied to clipboard

Playback rate change

Open hochstibe opened this issue 1 year ago • 0 comments

Description

The video source changes on user input. The user can also set a playback rate. I have 2 issues:

  • If the playback rate changed and a new video is loaded, an ExpressionChangedAfterItHasBeenCheckedError and it is resetted to the default Value
    • ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value for 'attr.aria-valuetext': '2'. Current value: '1'. Find more at https://angular.io/errors/NG0100
  • If the playback rate is set programmatically with this.api.playbackRate = 2;, the same Error occurs, but the rate changes to the given value.

The documentation states, that the Media Directive should have the attribute playbackRate, but it is not possible to set with this.api.getDefaultMedia().playbackRate = 2;. Maybe this is linked to the issue?

Demo: ngx-videogular-showroom adapted

 
import { Component } from "@angular/core";
import { Subscription } from 'rxjs';
import { VgApiService } from '@videogular/ngx-videogular/core';
 

export interface IMedia {
    title: string;
    src: string;
    type: string;
}


@Component({
    selector: "app-smart-playlist",
    template: `
        <div>
            <vg-player (onPlayerReady)="onPlayerReady($event)">
            <vg-buffering></vg-buffering>
        
            <vg-controls>
                <vg-play-pause></vg-play-pause>
                <vg-playback-button [playbackValues]="playbackValues"></vg-playback-button>
        
                <vg-time-display vgProperty="current" vgFormat="mm:ss"></vg-time-display>
        
                <vg-scrub-bar>
                    <vg-scrub-bar-current-time></vg-scrub-bar-current-time>
                    <vg-scrub-bar-buffering-time></vg-scrub-bar-buffering-time>
                </vg-scrub-bar>
        
                <vg-time-display vgProperty="total" vgFormat="mm:ss"></vg-time-display>
        
                <vg-mute></vg-mute>
                <vg-volume></vg-volume>
        
                <vg-fullscreen></vg-fullscreen>
            </vg-controls>
        
            <video #media
                [vgMedia]="media"
                [src]="currentItem.src"
                id="singleVideo"
                preload="auto"
                crossorigin>
            </video>
        </vg-player>

        <button (click)="setRate()">Set Rate = 2</button>
        
        <ul>
            <li *ngFor="let item of playlist; let $index = index"
                (click)="onClickPlaylistItem(item, $index)"
                [class.selected]="item === currentItem">
                {{ item.title }}
            </li>
        </ul>
    </div>
    `,
    styles: [
        `
        vg-player {
            height: 50%;
        }
        ul {
            list-style-type: none;
            margin: 0;
            padding: 0;
            font-family: sans-serif;
        }
        
        ul li {
            padding: 10px;
            cursor: pointer;
        }
        
        ul li.selected {
            background-color: #dddddd;
        }
        
        ul li:hover {
            background-color: #cce6ee;
        }
        `
    ]
})
export class SmartPlaylistComponent {
    
    public playbackValues: string[];

    playlist: Array<IMedia> = [
        {
            title: 'Pale Blue Dot',
            src: 'http://static.videogular.com/assets/videos/videogular.mp4',
            type: 'video/mp4',
        },
        {
            title: 'Big Buck Bunny',
            src:
                'http://static.videogular.com/assets/videos/big_buck_bunny_720p_h264.mov',
            type: 'video/mp4',
        },
        {
            title: 'Elephants Dream',
            src:
                'http://static.videogular.com/assets/videos/elephants-dream.mp4',
            type: 'video/mp4',
        },
    ];
    currentIndex = 0;
    currentItem: IMedia = this.playlist[this.currentIndex];
    api: VgApiService;

    
 
    constructor(
        ) {
            this.playbackValues = ['0.25', '0.5', '1.0', '1.5', '2.0'];
        }
 
    onPlayerReady(api: VgApiService) {
        this.api = api;

        this.api
            .getDefaultMedia()
            .subscriptions.loadedMetadata.subscribe(() => {
                this.playVideo.bind(this);
                console.info('Rate after video loaded', this.api.playbackRate);
            });

        this.api
            .getDefaultMedia()
            .subscriptions.ended.subscribe(this.nextVideo.bind(this));

        this.api
            .getDefaultMedia()
            .subscriptions.rateChange.subscribe(_ => {
                console.info('rate Changed', this.api.playbackRate);
            });
    }

    nextVideo() {
        let currentRate = this.api.playbackRate;
        console.info('Rate before video changed', currentRate);
        this.currentIndex++;

        if (this.currentIndex === this.playlist.length) {
            this.currentIndex = 0;
        }

        this.currentItem = this.playlist[this.currentIndex];
    }

    playVideo() {
        this.api.play();
    }

    onClickPlaylistItem(item: IMedia, index: number) {
        this.currentIndex = index;
        this.currentItem = item;
    }

    setRate() {
        this.api.playbackRate = 2;
    }
}

Expected Behavior

  • Playback rate should be the same, if the video changes
  • Playback rate change with the api should not trigger the error

Actual Behavior

  • Because of the ExpressionChangedError, the rate is reset to the default value
  • Error is raised when setting the rate programmatically

Steps to Reproduce

  • Change the rate
    • Next video -> Error and reset to default value
  • Change the rate with the button
    • Error, but change is applied

Attachments

Try to include screenshots for bugs or design assets for enhancements

hochstibe avatar Jan 10 '23 07:01 hochstibe