From f939c16cca2ff1e095f0e4ffb5f71692c7ef9213 Mon Sep 17 00:00:00 2001 From: Raul Date: Mon, 5 Jun 2017 16:41:49 +0200 Subject: [PATCH] fix(core): Fix buffering interoperability between plugins This fix avoid to see at the same time buffering icon and playing icon. --- src/buffering/vg-buffering.spec.ts | 45 +++--------------------- src/buffering/vg-buffering.ts | 29 +++++++-------- src/core/vg-media/i-playable.ts | 43 +++++++++++----------- src/core/vg-media/vg-media.ts | 35 ++++++++---------- src/overlay-play/vg-overlay-play.spec.ts | 7 +++- src/overlay-play/vg-overlay-play.ts | 15 ++++++++ 6 files changed, 75 insertions(+), 99 deletions(-) diff --git a/src/buffering/vg-buffering.spec.ts b/src/buffering/vg-buffering.spec.ts index ef54bc2f..b8a91d47 100644 --- a/src/buffering/vg-buffering.spec.ts +++ b/src/buffering/vg-buffering.spec.ts @@ -34,49 +34,14 @@ describe('Buffering', () => { }); }); - describe('isBuffering', ()=>{ - it('should show if buffer is detected and video is playing', () => { - vgBuffering.target = { - state: VgStates.VG_PLAYING - }; - - spyOn(vgBuffering, 'show'); + describe('isBuffering', ()=> { + it('should show if buffer is detected', () => { vgBuffering.onUpdateBuffer(true); - expect(vgBuffering.show).toHaveBeenCalled(); + expect(vgBuffering.isBuffering).toBe(true); }); - it('should hide if buffer is not detected and video is playing', () => { - vgBuffering.target = { - state: VgStates.VG_PLAYING - }; - - spyOn(vgBuffering, 'hide'); + it('should hide if buffer is not detected', () => { vgBuffering.onUpdateBuffer(false); - expect(vgBuffering.hide).toHaveBeenCalled(); - }); - it('should hide if buffer is detected and video is not playing', () => { - vgBuffering.target = { - state: VgStates.VG_PAUSED - }; - - spyOn(vgBuffering, 'hide'); - vgBuffering.onUpdateBuffer(true); - expect(vgBuffering.hide).toHaveBeenCalled(); - }); - }); - - describe('show', ()=>{ - it('should set displayState to "block"', () => { - vgBuffering.displayState = 'none'; - vgBuffering.show(); - expect(vgBuffering.displayState).toBe('block'); - }); - }); - - describe('hide', ()=>{ - it('should set displayState to "none"', () => { - vgBuffering.displayState = 'block'; - vgBuffering.hide(); - expect(vgBuffering.displayState).toBe('none'); + expect(vgBuffering.isBuffering).toBe(false); }); }); }); diff --git a/src/buffering/vg-buffering.ts b/src/buffering/vg-buffering.ts index 3251dfae..6fb35d7b 100644 --- a/src/buffering/vg-buffering.ts +++ b/src/buffering/vg-buffering.ts @@ -14,8 +14,14 @@ import { Subscription } from 'rxjs/Subscription'; `, styles: [ ` vg-buffering { + display: none; z-index: 201; } + + vg-buffering.is-buffering { + display: block; + } + .vg-buffering { position: absolute; display: block; @@ -106,7 +112,7 @@ export class VgBuffering implements OnInit, OnDestroy { subscriptions: Subscription[] = []; - @HostBinding('style.display') displayState: string = 'none'; + @HostBinding('class.is-buffering') isBuffering: boolean = false; constructor(ref: ElementRef, public API: VgAPI) { this.elem = ref.nativeElement; @@ -126,26 +132,15 @@ export class VgBuffering implements OnInit, OnDestroy { onPlayerReady() { this.target = this.API.getMediaById(this.vgFor); - this.target.subscriptions.bufferDetected.subscribe( - isBuffering => this.onUpdateBuffer(isBuffering) + this.subscriptions.push( + this.target.subscriptions.bufferDetected.subscribe( + isBuffering => this.onUpdateBuffer(isBuffering) + ) ); } onUpdateBuffer(isBuffering) { - if (isBuffering && this.target.state === VgStates.VG_PLAYING) { - this.show(); - } - else { - this.hide(); - } - } - - show() { - this.displayState = 'block'; - } - - hide() { - this.displayState = 'none'; + this.isBuffering = isBuffering; } ngOnDestroy() { diff --git a/src/core/vg-media/i-playable.ts b/src/core/vg-media/i-playable.ts index 085d6697..daa34fd6 100644 --- a/src/core/vg-media/i-playable.ts +++ b/src/core/vg-media/i-playable.ts @@ -1,31 +1,32 @@ -import {Observable} from "rxjs/Observable"; +import { Observable } from 'rxjs/Observable'; +import { Subject } from 'rxjs/Subject'; export interface IPlayable { - id:string; - elem:any; - time:any; - buffer:any; - track?:any; - canPlay:boolean; - canPlayThrough:boolean; - isMetadataLoaded:boolean; - isWaiting:boolean; - isCompleted:boolean; - isLive:boolean; + id: string; + elem: any; + time: any; + buffer: any; + track?: any; + canPlay: boolean; + canPlayThrough: boolean; + isMetadataLoaded: boolean; + isWaiting: boolean; + isCompleted: boolean; + isLive: boolean; textTracks: TextTrack[]; - state:string; - subscriptions:IMediaSubscriptions; - duration:number; - currentTime:number; - play:Function; - pause:Function; - addTextTrack?:Function; - dispatchEvent?:Function; + state: string; + subscriptions: IMediaSubscriptions; + duration: number; + currentTime: number; + play: Function; + pause: Function; + addTextTrack?: Function; + dispatchEvent?: Function; } export interface IMediaSubscriptions { abort: Observable; - bufferDetected: Observable; + bufferDetected: Subject; canPlay: Observable; canPlayThrough: Observable; durationChange: Observable; diff --git a/src/core/vg-media/vg-media.ts b/src/core/vg-media/vg-media.ts index d2a1e7cf..47b27972 100644 --- a/src/core/vg-media/vg-media.ts +++ b/src/core/vg-media/vg-media.ts @@ -7,6 +7,7 @@ import { Observer } from "rxjs/Observer"; import { VgStates } from '../states/vg-states'; import { VgAPI } from '../services/vg-api'; import { VgEvents } from '../events/vg-events'; +import { Subject } from 'rxjs/Subject'; import 'rxjs/add/observable/fromEvent'; import 'rxjs/add/observable/combineLatest'; @@ -41,7 +42,6 @@ export class VgMedia implements OnInit, OnDestroy, IPlayable { currentPlayPos: number = 0; lastPlayPos: number = 0; - bufferObserver: Observer; checkBufferSubscription: any; syncSubscription: Subscription; canPlayAllSubscription: any; @@ -61,6 +61,8 @@ export class VgMedia implements OnInit, OnDestroy, IPlayable { volumeChangeObs: Subscription; errorObs: Subscription; + bufferDetected: Subject = new Subject(); + constructor(private api: VgAPI, private ref: ChangeDetectorRef) { } @@ -124,15 +126,7 @@ export class VgMedia implements OnInit, OnDestroy, IPlayable { ), // Custom buffering detection - bufferDetected: Observable.create( - (observer: any) => { - this.bufferObserver = observer; - - return () => { - observer.disconnect(); - }; - } - ) + bufferDetected: this.bufferDetected }; this.mutationObs = this.subscriptions.mutation.subscribe(this.onMutation.bind(this)); @@ -219,7 +213,10 @@ export class VgMedia implements OnInit, OnDestroy, IPlayable { this.vgMedia.pause(); this.vgMedia.currentTime = 0; + // Start buffering until we can play the media file this.stopBufferCheck(); + this.isBufferDetected = true; + this.bufferDetected.next(this.isBufferDetected); // Only load src file if it's not a blob (for DASH / HLS sources) if (mut.target['src'] && mut.target['src'].length > 0 && mut.target['src'].indexOf('blob:') < 0) { @@ -288,11 +285,15 @@ export class VgMedia implements OnInit, OnDestroy, IPlayable { } onCanPlay(event: any) { + this.isBufferDetected = false; + this.bufferDetected.next(this.isBufferDetected); this.canPlay = true; this.ref.detectChanges(); } onCanPlayThrough(event: any) { + this.isBufferDetected = false; + this.bufferDetected.next(this.isBufferDetected); this.canPlayThrough = true; this.ref.detectChanges(); } @@ -339,9 +340,7 @@ export class VgMedia implements OnInit, OnDestroy, IPlayable { } } - if (this.bufferObserver) { - this.startBufferCheck(); - } + this.startBufferCheck(); this.ref.detectChanges(); } @@ -354,9 +353,7 @@ export class VgMedia implements OnInit, OnDestroy, IPlayable { } } - if (this.bufferObserver) { - this.stopBufferCheck(); - } + this.stopBufferCheck(); this.ref.detectChanges(); } @@ -407,7 +404,7 @@ export class VgMedia implements OnInit, OnDestroy, IPlayable { this.isBufferDetected = false; } - this.bufferObserver.next(this.isBufferDetected); + this.bufferDetected.next(this.isBufferDetected); this.lastPlayPos = this.currentPlayPos; } @@ -427,9 +424,7 @@ export class VgMedia implements OnInit, OnDestroy, IPlayable { this.isBufferDetected = false; - if (this.bufferObserver) { - this.bufferObserver.next(this.isBufferDetected); - } + this.bufferDetected.next(this.isBufferDetected); } seekTime(value:number, byPercent:boolean = false) { diff --git a/src/overlay-play/vg-overlay-play.spec.ts b/src/overlay-play/vg-overlay-play.spec.ts index 855aef97..e91a67e3 100644 --- a/src/overlay-play/vg-overlay-play.spec.ts +++ b/src/overlay-play/vg-overlay-play.spec.ts @@ -33,12 +33,17 @@ describe('Videogular Player', () => { }); it('Should get media by id on init', () => { - spyOn(api, 'getMediaById').and.callFake(() => { }); + spyOn(api, 'getMediaById').and.returnValue({ + subscriptions: { + bufferDetected: {subscribe: jasmine.createSpy('bufferDetected') } + } + }); overlayPlay.vgFor = 'test'; overlayPlay.onPlayerReady(); expect(api.getMediaById).toHaveBeenCalledWith('test'); + expect(overlayPlay.target.subscriptions.bufferDetected.subscribe).toHaveBeenCalled(); }); describe('onClick', () => { diff --git a/src/overlay-play/vg-overlay-play.ts b/src/overlay-play/vg-overlay-play.ts index f132b5a2..c5aff672 100644 --- a/src/overlay-play/vg-overlay-play.ts +++ b/src/overlay-play/vg-overlay-play.ts @@ -23,6 +23,10 @@ import { VgControlsHidden } from '../core/services/vg-controls-hidden'; z-index: 200; } + vg-overlay-play.is-buffering { + display: none; + } + vg-overlay-play .vg-overlay-play { transition: all 0.5s; cursor: pointer; @@ -71,6 +75,8 @@ export class VgOverlayPlay implements OnInit, OnDestroy { subscriptions: Subscription[] = []; + @HostBinding('class.is-buffering') isBuffering: boolean = false; + constructor(ref: ElementRef, public API: VgAPI, public fsAPI: VgFullscreenAPI, private controlsHidden: VgControlsHidden) { this.elem = ref.nativeElement; } @@ -88,6 +94,15 @@ export class VgOverlayPlay implements OnInit, OnDestroy { this.target = this.API.getMediaById(this.vgFor); this.subscriptions.push(this.fsAPI.onChangeFullscreen.subscribe(this.onChangeFullscreen.bind(this))); this.subscriptions.push(this.controlsHidden.isHidden.subscribe(this.onHideControls.bind(this))); + this.subscriptions.push( + this.target.subscriptions.bufferDetected.subscribe( + isBuffering => this.onUpdateBuffer(isBuffering) + ) + ); + } + + onUpdateBuffer(isBuffering) { + this.isBuffering = isBuffering; } onChangeFullscreen(fsState: boolean) {