Skip to content

Commit

Permalink
Merge pull request #180 from bitmovin/feature/add-dvr-live-support
Browse files Browse the repository at this point in the history
Add support for `DVRLIVE`
  • Loading branch information
stonko1994 authored Oct 30, 2024
2 parents 3b75f13 + e39e5fd commit 0d8fb5e
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 12 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

### Added

- Support for the `DVRLIVE` PlaybackMode to not rely on Metadata parsing for live streams anymore

## [2.7.1] - 2024-10-03

### Fixed
Expand Down
4 changes: 4 additions & 0 deletions src/ts/BitmovinYospacePlayerAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ import type { AdBreak, CompanionAd } from 'bitmovin-player/modules/bitmovinplaye
// Enums

export enum YospaceAssetType {
/**
* @deprecated Use `DVRLIVE` instead for a wider compatibility
*/
LINEAR,
VOD,
DVRLIVE,
}

export enum YospacePlayerType {
Expand Down
47 changes: 38 additions & 9 deletions src/ts/InternalBitmovinYospacePlayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@ import {
BreakType,
CONNECTION_ERROR,
CONNECTION_TIMEOUT,
DEBUG_ALL,
DebugFlags,
MALFORMED_URL,
PlayerEvent as YsPlayerEvent,
ResourceType,
Session,
SessionDVRLive,
SessionLive,
SessionProperties,
SessionState,
SessionVOD,
TimedMetadata,
UNKNOWN_FORMAT,
YoLog,
DebugFlags,
} from '@yospace/admanagement-sdk';

import type {
Expand Down Expand Up @@ -53,8 +53,10 @@ import {
import { DefaultBitmovinYospacePlayerPolicy } from './BitmovinYospacePlayerPolicy';
import { ArrayUtils } from 'bitmovin-player-ui/dist/js/framework/arrayutils';
import {
AdImmunityConfig,
AdImmunityConfiguredEvent,
AdImmunityEndedEvent,
AdImmunityStartedEvent,
BitmovinYospacePlayerAPI,
BitmovinYospacePlayerPolicy,
CompanionAdType,
Expand All @@ -72,8 +74,6 @@ import {
YospacePolicyErrorCode,
YospacePolicyErrorEvent,
YospaceSourceConfig,
AdImmunityStartedEvent,
AdImmunityConfig,
} from './BitmovinYospacePlayerAPI';
import { YospacePlayerError } from './YospaceError';
import type {
Expand Down Expand Up @@ -163,6 +163,9 @@ export class InternalBitmovinYospacePlayer implements BitmovinYospacePlayerAPI {
private adImmunityCountDown: number | null = null;
private unpauseAfterSeek = false;

// Holds the first timeChangedValue in case we have a DVRLIVE asset. See onTimeChanged for details.
private streamStartTimeOffset = 0;

constructor(containerElement: HTMLElement, player: PlayerAPI, yospaceConfig: YospaceConfiguration = {}) {
this.yospaceConfig = yospaceConfig;
Logger.log('[BitmovinYospacePlayer] loading YospacePlayer with config= ' + stringify(this.yospaceConfig));
Expand Down Expand Up @@ -202,11 +205,12 @@ export class InternalBitmovinYospacePlayer implements BitmovinYospacePlayerAPI {
return;
}
this.resetState();
this.registerPlayerEvents();

const url = source.hls || source.dash;

this.yospaceSourceConfig = source;

this.registerPlayerEvents();

const onInitComplete = (event: any) => {
const session: Session = event.getPayload();
const state = session.getSessionState();
Expand Down Expand Up @@ -307,6 +311,9 @@ export class InternalBitmovinYospacePlayer implements BitmovinYospacePlayerAPI {
case YospaceAssetType.VOD:
SessionVOD.create(url, properties, onInitComplete);
break;
case YospaceAssetType.DVRLIVE:
SessionDVRLive.create(url, properties, onInitComplete);
break;
default:
Logger.error('Undefined YospaceSourceConfig.assetType; Could not obtain session;');
}
Expand Down Expand Up @@ -952,6 +959,7 @@ export class InternalBitmovinYospacePlayer implements BitmovinYospacePlayerAPI {
this.cachedSeekTarget = null;
this.truexAdFree = undefined;
this.startSent = false;
this.streamStartTimeOffset = 0;
}

private handleQuartileEvent(adQuartileEventName: string): void {
Expand Down Expand Up @@ -1185,8 +1193,10 @@ export class InternalBitmovinYospacePlayer implements BitmovinYospacePlayerAPI {
this.player.on(this.player.exports.PlayerEvent.Muted, this.onMuted);
this.player.on(this.player.exports.PlayerEvent.Unmuted, this.onUnmuted);

// To support ads in live streams we need to track metadata events
this.player.on(this.player.exports.PlayerEvent.Metadata, this.onMetaData);
if (this.yospaceSourceConfig.assetType === YospaceAssetType.LINEAR) {
// To support ads in live streams we need to track metadata events
this.player.on(this.player.exports.PlayerEvent.Metadata, this.onMetaData);
}
}

private unregisterPlayerEvents(): void {
Expand Down Expand Up @@ -1277,7 +1287,26 @@ export class InternalBitmovinYospacePlayer implements BitmovinYospacePlayerAPI {
this.lastTimeChangedTime = event.time;

if (timeDifference >= 0 || timeDifference < -0.25) {
this.session.onPlayheadUpdate(toMilliseconds(event.time));
let playheadTime: number;

if (this.yospaceSourceConfig.assetType === YospaceAssetType.DVRLIVE) {
if (!this.streamStartTimeOffset) {
// The `session.onPlayheadUpdate` requires to report the playback time relative from the point of joining
// the stream, starting with 0. However, our player does not start at 0 when joining the stream.
// Depending on the streaming technology (HLS vs DASH) this value is something else. Sometimes it's
// `getMaxTimeShift()` but also other values were observed.
// When we assume that the very first `timeChangeEvent` is the time of joining the stream, we can take
// this value and use it as the offset for subsequent calculations.
this.streamStartTimeOffset = this.player.getCurrentTime('relativetime' as any);
}

playheadTime = this.player.getCurrentTime('relativetime' as any) - this.streamStartTimeOffset;
} else {
playheadTime = event.time;
}

Logger.log('[BitmovinYospacePlayer] - reporting playhead time to Yospace:', playheadTime);
this.session.onPlayheadUpdate(toMilliseconds(playheadTime));
} else {
Logger.warn('Encountered a small negative TimeChanged update, not reporting to Yospace. Difference was: ' + timeDifference);
}
Expand Down
12 changes: 9 additions & 3 deletions web/js/sources.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,17 @@ var sources = {
linear: {
yospaceValidation: {
title: 'Yospace Validation',
dash: 'https://csm-e-sdk-validation.bln1.yospace.com/csm/extlive/yosdk01,t2-dash.mpd?yo.av=3', // v0 emsg
// dash: 'https://csm-e-sdk-validation.bln1.yospace.com/csm/extlive/yosdk01,dash.mpd?yo.av=3', // v1 emsg
// hls: 'https://csm-e-sdk-validation.bln1.yospace.com/csm/extlive/yospace02,hlssample42.m3u8?yo.br=true&yo.av=3',
// dash: 'https://csm-e-sdk-validation.bln1.yospace.com/csm/extlive/yosdk02,dash-mp4.mpd?yo.br=true&yo.av=4',
hls: 'https://csm-e-sdk-validation.bln1.yospace.com/csm/extlive/yosdk02,hls-ts.m3u8?yo.br=true&yo.av=4',
// Yospace configuration
assetType: bitmovin.player.ads.yospace.YospaceAssetType.LINEAR,
},
dvrLive: {
title: 'DVR Live',
// dash: 'https://csm-e-sdk-validation.bln1.yospace.com/csm/extlive/yosdk02,dash-mp4-pre.mpd?yo.br=false&yo.av=4&yo.lp=true',
hls: 'https://csm-e-sdk-validation.bln1.yospace.com/csm/extlive/yosdk02,hls-ts-pre.m3u8?yo.br=false&yo.av=4&yo.lp=true',
// Yospace configuration
assetType: bitmovin.player.ads.yospace.YospaceAssetType.DVRLIVE,
},
},
};

0 comments on commit 0d8fb5e

Please sign in to comment.