Skip to content

Commit

Permalink
fix: move state to player
Browse files Browse the repository at this point in the history
  • Loading branch information
adrums86 committed Feb 10, 2025
1 parent 87ce914 commit 9fd9c3a
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 48 deletions.
3 changes: 0 additions & 3 deletions packages/playback/src/lib/pipelines/base-pipeline.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { IPipeline, IPipelineDependencies } from '../types/pipeline.declarations';
import { PlayerTimeRange } from '../models/player-time-range';
import type { PlaybackState } from '../consts/playback-state';
import type { IPlaybackStats } from '../types/playback-stats.declarations';
import type { INetworkManager } from '../types/network.declarations';
import type { IQualityLevel } from '../types/quality-level.declarations';
Expand Down Expand Up @@ -46,8 +45,6 @@ export abstract class BasePipeline implements IPipeline {

public abstract getThumbnailTracks(): Array<IPlayerThumbnailTrack>;

public abstract getPlaybackState(): PlaybackState;

public abstract start(): void;

public getPlaybackStats(): IPlaybackStats {
Expand Down
13 changes: 0 additions & 13 deletions packages/playback/src/lib/pipelines/native/native-pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type { IPipelineDependencies } from '../../types/pipeline.declarations';
import type { IPlayerAudioTrack } from '../../types/audio-track.declarations';
import { PlayerAudioTrack } from '../../models/player-audio-track';
import type { IQualityLevel } from '../../types/quality-level.declarations';
import { PlaybackState } from '../../consts/playback-state';
import type { IPlayerTextTrack } from '../../types/text-track.declarations';
import {
type IRemoteVttThumbnailTrackOptions,
Expand All @@ -14,13 +13,8 @@ import { PlayerThumbnailTrack } from '../../models/player-thumbnail-tracks';
import { TextTrackKind, TextTrackMode, Thumbnails } from '../../consts/text-tracks';

export class NativePipeline extends BasePipeline {
private playbackState_: PlaybackState = PlaybackState.Idle;

private constructor(dependencies: IPipelineDependencies) {
super(dependencies);
this.videoElement_.onwaiting = (): void => {
this.playbackState_ = PlaybackState.Buffering;
};
}

public static create(dependencies: IPipelineDependencies): NativePipeline {
Expand Down Expand Up @@ -76,9 +70,6 @@ export class NativePipeline extends BasePipeline {
}
return [];

Check warning on line 71 in packages/playback/src/lib/pipelines/native/native-pipeline.ts

View check run for this annotation

Codecov / codecov/patch

packages/playback/src/lib/pipelines/native/native-pipeline.ts#L71

Added line #L71 was not covered by tests
}
public getPlaybackState(): PlaybackState {
return this.playbackState_;
}

public getAudioTracks(): Array<IPlayerAudioTrack> {
if (this.videoElement_.audioTracks) {
Expand Down Expand Up @@ -127,22 +118,18 @@ export class NativePipeline extends BasePipeline {

// TODO: check for autoplay/preload/etc
this.videoElement_.load();
this.playbackState_ = PlaybackState.Loading;
}

public dispose(): void {
this.videoElement_.removeAttribute('src');
this.videoElement_.load();
this.playbackState_ = PlaybackState.Idle;
}

public play(): void {
super.play();
this.playbackState_ = PlaybackState.Playing;
}

Check warning on line 130 in packages/playback/src/lib/pipelines/native/native-pipeline.ts

View check run for this annotation

Codecov / codecov/patch

packages/playback/src/lib/pipelines/native/native-pipeline.ts#L129-L130

Added lines #L129 - L130 were not covered by tests

public pause(): void {
super.pause();
this.playbackState_ = PlaybackState.Paused;
}

Check warning on line 134 in packages/playback/src/lib/pipelines/native/native-pipeline.ts

View check run for this annotation

Codecov / codecov/patch

packages/playback/src/lib/pipelines/native/native-pipeline.ts#L133-L134

Added lines #L133 - L134 were not covered by tests
}
8 changes: 8 additions & 0 deletions packages/playback/src/lib/player/base-player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ export abstract class BasePlayer {
this.activeVideoElement_.addEventListener('volumechange', this.handleVolumeChange_);
this.activeVideoElement_.addEventListener('ratechange', this.handleRateChange_);
this.activeVideoElement_.addEventListener('timeupdate', this.handleTimeUpdate_);
this.activeVideoElement_.addEventListener('waiting', this.handleWaiting_);

Check warning on line 403 in packages/playback/src/lib/player/base-player.ts

View check run for this annotation

Codecov / codecov/patch

packages/playback/src/lib/player/base-player.ts#L403

Added line #L403 was not covered by tests
// EME
this.activeVideoElement_.addEventListener('encrypted', this.handleEncryptedEvent_);
this.activeVideoElement_.addEventListener('waitingforkey', this.handleWaitingForKeyEvent_);
Expand Down Expand Up @@ -428,6 +429,7 @@ export abstract class BasePlayer {
this.activeVideoElement_.removeEventListener('volumechange', this.handleVolumeChange_);
this.activeVideoElement_.removeEventListener('ratechange', this.handleRateChange_);
this.activeVideoElement_.removeEventListener('timeupdate', this.handleTimeUpdate_);
this.activeVideoElement_.removeEventListener('waiting', this.handleWaiting_);

Check warning on line 432 in packages/playback/src/lib/player/base-player.ts

View check run for this annotation

Codecov / codecov/patch

packages/playback/src/lib/player/base-player.ts#L432

Added line #L432 was not covered by tests
// EME
this.activeVideoElement_.removeEventListener('encrypted', this.handleEncryptedEvent_);
this.activeVideoElement_.removeEventListener('waitingforkey', this.handleWaitingForKeyEvent_);
Expand Down Expand Up @@ -575,6 +577,10 @@ export abstract class BasePlayer {
this.eventEmitter_.emitEvent(new CurrentTimeChangedEvent(target.currentTime));
};

protected readonly handleWaiting_ = (): void => {
this.transitionPlaybackState_(PlaybackState.Buffering);
};

protected readonly handleEncryptedEvent_ = (event: MediaEncryptedEvent): void => {
this.logger_.debug('received encrypted event', event);

Expand Down Expand Up @@ -621,6 +627,7 @@ export abstract class BasePlayer {
*/
public play(): void {
this.activeVideoElement_?.play();
this.transitionPlaybackState_(PlaybackState.Playing);
// TODO: pass command to loader/pipeline
}

Expand All @@ -629,6 +636,7 @@ export abstract class BasePlayer {
*/
public pause(): void {
this.activeVideoElement_?.pause();
this.transitionPlaybackState_(PlaybackState.Paused);
// TODO: pass command to loader/pipeline
}

Expand Down
2 changes: 0 additions & 2 deletions packages/playback/src/lib/types/pipeline.declarations.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { PlaybackState } from '../consts/playback-state';
import type { IPlaybackStats } from './playback-stats.declarations';
import type { ILogger } from './logger.declarations';
import type { INetworkManager } from './network.declarations';
Expand Down Expand Up @@ -47,7 +46,6 @@ export interface IPipelineFactoryConfiguration {
export interface IPipeline {
play(): void;
pause(): void;
getPlaybackState(): PlaybackState;
seek(seekTarget: number): boolean;
getSeekableRanges(): Array<IPlayerTimeRange>;
getBufferedRanges(): Array<IPlayerTimeRange>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import type {
import { NativePipeline } from '../../../../src/lib/pipelines/native/native-pipeline';
import { beforeEach, describe, expect, it } from 'vitest';
import { TextTrackKind, TextTrackMode } from '../../../../src/lib/consts/text-tracks';
import { PlaybackState } from '../../../../src/lib/consts/playback-state';

describe('NativePipeline', () => {
let nativePipeline: NativePipeline;
Expand Down Expand Up @@ -209,30 +208,15 @@ describe('NativePipeline', () => {

it('should set src and state on start', () => {
const expectedSrc = 'https://foo.bar.m3u8/';
let expectedState = PlaybackState.Idle;
expect(videoElement.src).toBe('');
expect(nativePipeline.getPlaybackState()).toBe(expectedState);
nativePipeline.start();
expectedState = PlaybackState.Loading;
expect(videoElement.src).toEqual(expectedSrc);
expect(nativePipeline.getPlaybackState()).toBe(expectedState);
});

it('should remove src and state on dispose', () => {
nativePipeline.start();
nativePipeline.dispose();
expect(videoElement.src).toBe('');
expect(nativePipeline.getPlaybackState()).toEqual(PlaybackState.Idle);
});

it('should set state on play', () => {
nativePipeline.play();
expect(nativePipeline.getPlaybackState()).toEqual(PlaybackState.Playing);
});

it('should set state on pause', () => {
nativePipeline.pause();
expect(nativePipeline.getPlaybackState()).toEqual(PlaybackState.Paused);
});

it('getQualityLevels should return empty array', () => {
Expand All @@ -246,19 +230,5 @@ describe('NativePipeline', () => {
it('selectAutoQualityLevel should return false', () => {
expect(nativePipeline.selectAutoQualityLevel()).toBe(false);
});

it('state should be set to buffering on waiting', async () => {
const checkState = (): void => {
expect(nativePipeline.getPlaybackState()).toEqual(PlaybackState.Buffering);
};
expect(nativePipeline.getPlaybackState()).toEqual(PlaybackState.Idle);
// first waiting to set state.
const waitingEvent = new Event('waiting');
videoElement.dispatchEvent(waitingEvent);

// check state on second waiting.
videoElement.onwaiting = await checkState;
videoElement.dispatchEvent(waitingEvent);
});
});
});
20 changes: 20 additions & 0 deletions packages/playback/test/lib/player/player.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import type { PlayerEvent } from '../../../src/lib/events/base-player-event';
import { RequestType } from '../../../src/lib/consts/request-type';
import { ServiceLocator } from '../../../src/lib/service-locator';
import { PlaybackState } from '../../../src/lib/consts/playback-state';

describe('Player spec', () => {
let player: Player;
Expand Down Expand Up @@ -251,4 +252,23 @@ describe('Player spec', () => {
expect(expectedEvents).toEqual(actualEvents);
});
});

describe('state', () => {
it('should transition to playing', () => {
player.play();
expect(player.getPlaybackState()).toEqual(PlaybackState.Playing);
});

it('should transition to paused', () => {
player.pause();
expect(player.getPlaybackState()).toEqual(PlaybackState.Paused);
});

it('should transition to buffering', () => {
// cast as any to call handleWaiting directly.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(player as any).handleWaiting_();
expect(player.getPlaybackState()).toEqual(PlaybackState.Buffering);
});
});
});

0 comments on commit 9fd9c3a

Please sign in to comment.