Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Set default player init time for all elements for greater accuracy. Expose attr+prop for externally defined player init time. #1034

Merged
merged 7 commits into from
Dec 9, 2024
Merged
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
"publish-release": "lerna run publish-release --scope @mux/* --"
},
"resolutions": {
"@web/test-runner-chrome": "0.13.0",
"playwright": "1.45.3"
},
"packageManager": "yarn@1.22.21+sha256.dbed5b7e10c552ba0e1a545c948d5473bc6c5a28ce22a8fd27e493e3e5eb6370"
Expand Down
2 changes: 1 addition & 1 deletion packages/mux-active-viewer-count/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
"@typescript-eslint/parser": "^8.3.0",
"@web/dev-server-esbuild": "^1.0.2",
"@web/dev-server-import-maps": "^0.2.1",
"@web/test-runner": "^0.18.2",
"@web/test-runner": "^0.19.0",
"downlevel-dts": "^0.11.0",
"esbuild": "^0.19.8",
"eslint": "^9.9.1",
Expand Down
7 changes: 5 additions & 2 deletions packages/mux-audio-react/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export type Props = Omit<

export const playerSoftwareVersion = getPlayerVersion();
export const playerSoftwareName = 'mux-audio-react';
export { generatePlayerInitTime };

const MuxAudio = React.forwardRef<HTMLAudioElement | undefined, Partial<Props>>((props, ref) => {
const { playbackId, src: outerSrc, children, autoPlay, preload, tokens, playbackToken, ...restProps } = props;
Expand All @@ -33,7 +34,7 @@ const MuxAudio = React.forwardRef<HTMLAudioElement | undefined, Partial<Props>>(
Object.entries(restProps).filter(([key]) => !Object.keys(MuxAudio.propTypes as any).includes(key))
);

const [playerInitTime] = useState(generatePlayerInitTime());
const [playerInitTime] = useState(props.playerInitTime ?? generatePlayerInitTime());
const [src, setSrc] = useState<MuxMediaProps['src']>(toMuxVideoURL(props) ?? outerSrc);
const playbackCoreRef = useRef<PlaybackCore | undefined>(undefined);
const innerMediaElRef = useRef<HTMLAudioElement>(null);
Expand All @@ -45,9 +46,11 @@ const MuxAudio = React.forwardRef<HTMLAudioElement | undefined, Partial<Props>>(

useEffect(() => {
const propsWithState = {
// NOTE: Applying playerInitTime first as a simple way of overriding it if/when folks update
// the value via props after initial load (e.g. when swapping src)
playerInitTime,
...props,
src,
playerInitTime,
playerSoftwareName,
playerSoftwareVersion,
autoplay: autoPlay,
Expand Down
2 changes: 1 addition & 1 deletion packages/mux-audio/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"@typescript-eslint/parser": "^8.3.0",
"@web/dev-server-esbuild": "^1.0.2",
"@web/dev-server-import-maps": "^0.2.1",
"@web/test-runner": "^0.18.2",
"@web/test-runner": "^0.19.0",
"downlevel-dts": "^0.11.0",
"esbuild": "^0.19.8",
"eslint": "^9.9.1",
Expand Down
28 changes: 24 additions & 4 deletions packages/mux-audio/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { CustomAudioElement, Events as AudioEvents } from 'custom-media-element'
import type { HlsConfig } from 'hls.js';

export const Attributes = {
PLAYER_INIT_TIME: 'player-init-time',
ENV_KEY: 'env-key',
DEBUG: 'debug',
PLAYBACK_ID: 'playback-id',
Expand Down Expand Up @@ -66,18 +67,30 @@ class MuxAudioElement extends CustomAudioElement implements Partial<MuxMediaProp

#core?: PlaybackCore;
#loadRequested?: Promise<void> | null;
#playerInitTime: number;
#defaultPlayerInitTime: number;
#metadata: Readonly<Metadata> = {};
#tokens: Tokens = {};
#_hlsConfig?: Partial<HlsConfig>;

constructor() {
super();
this.#playerInitTime = generatePlayerInitTime();
this.#defaultPlayerInitTime = generatePlayerInitTime();
}

get playerInitTime() {
return this.#playerInitTime;
if (!this.hasAttribute(Attributes.PLAYER_INIT_TIME)) return this.#defaultPlayerInitTime;
return +(this.getAttribute(Attributes.PLAYER_INIT_TIME) as string) as number;
}

set playerInitTime(val) {
// don't cause an infinite loop and avoid change event dispatching
if (val == this.playerInitTime) return;

if (val == null) {
this.removeAttribute(Attributes.PLAYER_INIT_TIME);
} else {
this.setAttribute(Attributes.PLAYER_INIT_TIME, `${+val}`);
}
}

get playerSoftwareName() {
Expand Down Expand Up @@ -546,6 +559,13 @@ if (!globalThis.customElements.get('mux-audio')) {
globalThis.MuxAudioElement = MuxAudioElement;
}

export { PlaybackEngine, PlaybackEngine as Hls, ExtensionMimeTypeMap as MimeTypes, MediaError, AudioEvents };
export {
PlaybackEngine,
PlaybackEngine as Hls,
ExtensionMimeTypeMap as MimeTypes,
MediaError,
AudioEvents,
generatePlayerInitTime,
};

export default MuxAudioElement;
1 change: 1 addition & 0 deletions packages/mux-player-react/REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
| `metadata` | `object`\* | An object for configuring any metadata you'd like to send to [Mux Data](https://docs.mux.com/guides/data/make-your-data-actionable-with-metadata) | `undefined` |
| `tokens` | `object`\* | An object for setting all signed URL tokens with the signature `{ playback?: string; thumbnail?: string; storyboard?: string; drm?: string; }` | `undefined` |
| `castCustomData` | `object` (JSON-serializable) | [Custom Data](https://developers.google.com/cast/docs/reference/web_sender/chrome.cast.media.MediaInfo#customData) to send to your Google cast receiver on initial load. If none is provided, various Mux key/value pairs will be sent. | Mux-specific object |
| `playerInitTime` | `number` (timestamp) | Overrides the default [player initialization time](https://docs.mux.com/guides/make-your-data-actionable-with-metadata#optional-configurable-metadata), used by Mux Data for time-based [quality-of-experience (QOE) metrics](https://docs.mux.com/guides/understand-metric-definitions). It will be inferred from instantiation time by default. | Varies |
| `ref` | [React `ref`](https://reactjs.org/docs/refs-and-the-dom.html) | A [React `ref`](https://reactjs.org/docs/refs-and-the-dom.html) to the underlying [`MuxPlayerElement`](../mux-player/REFERENCE.md) web component | `undefined` |

<!-- UNDOCUMENTED
Expand Down
9 changes: 6 additions & 3 deletions packages/mux-player-react/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
'use client';
import React, { useEffect } from 'react';
import React, { useEffect, useState } from 'react';
import type { CSSProperties } from 'react';
import type {
StreamTypes,
Expand All @@ -9,7 +9,7 @@ import type {
MinResolutionValue,
RenditionOrderValue,
} from '@mux/playback-core';
import { MaxResolution, MinResolution, RenditionOrder } from '@mux/playback-core';
import { MaxResolution, MinResolution, RenditionOrder, generatePlayerInitTime } from '@mux/playback-core';
import { MediaError } from '@mux/mux-player';
import type MuxPlayerElement from '@mux/mux-player';
import type { Tokens, MuxPlayerElementEventMap } from '@mux/mux-player';
Expand All @@ -19,7 +19,7 @@ import { useCombinedRefs } from './useCombinedRefs';
import useObjectPropEffect, { defaultHasChanged } from './useObjectPropEffect';
import { getPlayerVersion } from './env';

export { MediaError, MaxResolution, MinResolution, RenditionOrder };
export { MediaError, MaxResolution, MinResolution, RenditionOrder, generatePlayerInitTime };

type ValueOf<T> = T[keyof T];
interface GenericEventListener<T extends Event = CustomEvent> {
Expand Down Expand Up @@ -79,6 +79,7 @@ export type MuxPlayerProps = {
defaultHiddenCaptions?: boolean;
playerSoftwareVersion?: string;
playerSoftwareName?: string;
playerInitTime?: number;
forwardSeekOffset?: number;
backwardSeekOffset?: number;
maxResolution?: MaxResolutionValue;
Expand Down Expand Up @@ -267,13 +268,15 @@ const MuxPlayer = React.forwardRef<
const innerPlayerRef = useRef<MuxPlayerElement>(null);
const playerRef = useCombinedRefs(innerPlayerRef, ref);
const [remainingProps] = usePlayer(innerPlayerRef, props);
const [playerInitTime] = useState(props.playerInitTime ?? generatePlayerInitTime());

return (
<MuxPlayerInternal
/** @TODO Fix types relationships (CJP) */
ref={playerRef as typeof innerPlayerRef}
playerSoftwareName={playerSoftwareName}
playerSoftwareVersion={playerSoftwareVersion}
playerInitTime={playerInitTime}
{...remainingProps}
/>
);
Expand Down
2 changes: 2 additions & 0 deletions packages/mux-player/REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
| `placeholder` | `string` (URI) | Image to show as various assets load. Typically a [data URI](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs) when used | N/A |
| `cast-receiver` | `string` (Receiver ID) | The app ID to use for a custom [Google cast receiver](https://developers.google.com/cast/docs/web_receiver/basic). If none is provided, the default receiver app will be used. | N/A |
| `no-tooltips` | `boolean` | Toggles disabling tooltips in the UI | `false` |
| `player-init-time` | `number` (timestamp) | Overrides the default [player initialization time](https://docs.mux.com/guides/make-your-data-actionable-with-metadata#optional-configurable-metadata), used by Mux Data for time-based [quality-of-experience (QOE) metrics](https://docs.mux.com/guides/understand-metric-definitions). It will be inferred from instantiation time by default. | Varies |

<!-- UNDOCUMENTED
// NEW STREAM TYPE VALUES
Expand Down Expand Up @@ -158,6 +159,7 @@
| `activeChapter` <sub><sup>Read only</sup></sub> | `{ startTime: number; endTime?: number, value: string; }` | The current active Chapter, determined based on the player's `currentTime`. | `undefined` |
| `castReceiver` | `string` (Receiver ID) | The app ID to use for a custom [Google cast receiver](https://developers.google.com/cast/docs/web_receiver/basic). If none is provided, the default receiver app will be used. | `undefined` |
| `castCustomData` | `object` (JSON-serializable) | [Custom Data](https://developers.google.com/cast/docs/reference/web_sender/chrome.cast.media.MediaInfo#customData) to send to your Google cast receiver on initial load. If none is provided, various Mux key/value pairs will be sent. | Mux-specific object |
| `playerInitTime` | `number` (timestamp) | Overrides the default [player initialization time](https://docs.mux.com/guides/make-your-data-actionable-with-metadata#optional-configurable-metadata), used by Mux Data for time-based [quality-of-experience (QOE) metrics](https://docs.mux.com/guides/understand-metric-definitions). It will be inferred from instantiation time by default. | Varies |

<!-- UNDOCUMENTED
// NEW STREAM TYPE VALUES
Expand Down
2 changes: 1 addition & 1 deletion packages/mux-player/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@
"@web/dev-server-esbuild": "^1.0.2",
"@web/dev-server-import-maps": "^0.2.1",
"@web/dev-server-legacy": "^2.1.1",
"@web/test-runner": "^0.18.2",
"@web/test-runner": "^0.19.0",
"@web/test-runner-playwright": "^0.11.0",
"@web/test-runner-saucelabs": "^0.11.2",
"downlevel-dts": "^0.11.0",
Expand Down
22 changes: 21 additions & 1 deletion packages/mux-player/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
i18n,
parseJwt,
MuxJWTAud,
generatePlayerInitTime,
} from '@mux/playback-core';
import type {
ValueOf,
Expand Down Expand Up @@ -48,7 +49,7 @@ const DefaultThemeName = 'gerwig';

export type { Tokens };

export { MediaError };
export { MediaError, generatePlayerInitTime };

const VideoAttributes = {
SRC: 'src',
Expand Down Expand Up @@ -148,6 +149,7 @@ function getProps(el: MuxPlayerElement, state?: any): MuxTemplateProps {
assetEndTime: el.assetEndTime,
renditionOrder: el.renditionOrder,
metadata: el.metadata,
playerInitTime: el.playerInitTime,
playerSoftwareName: el.playerSoftwareName,
playerSoftwareVersion: el.playerSoftwareVersion,
startTime: el.startTime,
Expand Down Expand Up @@ -311,6 +313,7 @@ interface MuxPlayerElement

// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
class MuxPlayerElement extends VideoApiElement implements MuxPlayerElement {
#defaultPlayerInitTime: number;
#isInit = false;
#tokens: Tokens = {};
#userInactive = true;
Expand Down Expand Up @@ -351,6 +354,7 @@ class MuxPlayerElement extends VideoApiElement implements MuxPlayerElement {

constructor() {
super();
this.#defaultPlayerInitTime = generatePlayerInitTime();

this.attachShadow({ mode: 'open' });
this.#setupCSSProperties();
Expand Down Expand Up @@ -1270,6 +1274,22 @@ class MuxPlayerElement extends VideoApiElement implements MuxPlayerElement {
}
}

get playerInitTime() {
if (!this.hasAttribute(MuxVideoAttributes.PLAYER_INIT_TIME)) return this.#defaultPlayerInitTime;
return toNumberOrUndefined(this.getAttribute(MuxVideoAttributes.PLAYER_INIT_TIME));
}

set playerInitTime(val) {
// don't cause an infinite loop and avoid change event dispatching
if (val == this.playerInitTime) return;

if (val == null) {
this.removeAttribute(MuxVideoAttributes.PLAYER_INIT_TIME);
} else {
this.setAttribute(MuxVideoAttributes.PLAYER_INIT_TIME, `${+val}`);
}
}

/**
* Get the player software name. Used by Mux Data.
*/
Expand Down
1 change: 1 addition & 0 deletions packages/mux-player/src/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ export const content = (props: MuxTemplateProps) => html`
prefer-playback="${props.preferPlayback ?? false}"
start-time="${props.startTime != null ? props.startTime : false}"
beacon-collection-domain="${props.beaconCollectionDomain ?? false}"
player-init-time="${props.playerInitTime ?? false}"
player-software-name="${props.playerSoftwareName ?? false}"
player-software-version="${props.playerSoftwareVersion ?? false}"
env-key="${props.envKey ?? false}"
Expand Down
2 changes: 1 addition & 1 deletion packages/mux-player/test/web-test-runner.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const config = {
include: ['src/**/*'],
},
testsFinishTimeout: 600000,
browsers: [chromeLauncher({ launchOptions: { args: ['--headless=old'] } })],
browsers: [chromeLauncher({})],
};

if (process.argv.some((arg) => arg.includes('--all'))) {
Expand Down
2 changes: 1 addition & 1 deletion packages/mux-uploader/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
"@open-wc/testing": "^4.0.0",
"@web/dev-server-esbuild": "^1.0.2",
"@web/dev-server-import-maps": "^0.2.1",
"@web/test-runner": "^0.18.2",
"@web/test-runner": "^0.19.0",
"copyfiles": "^2.4.1",
"downlevel-dts": "^0.11.0",
"esbuild": "^0.19.8",
Expand Down
7 changes: 5 additions & 2 deletions packages/mux-video-react/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export type Props = Omit<

export const playerSoftwareVersion = getPlayerVersion();
export const playerSoftwareName = 'mux-video-react';
export { generatePlayerInitTime };

const MuxVideo = React.forwardRef<HTMLVideoElement | undefined, Partial<Props>>((props, ref) => {
const {
Expand All @@ -43,7 +44,7 @@ const MuxVideo = React.forwardRef<HTMLVideoElement | undefined, Partial<Props>>(
Object.entries(restProps).filter(([key]) => !Object.keys(MuxVideo.propTypes as any).includes(key))
);

const [playerInitTime] = useState(generatePlayerInitTime());
const [playerInitTime] = useState(props.playerInitTime ?? generatePlayerInitTime());
const [src, setSrc] = useState<MuxMediaProps['src']>(toMuxVideoURL(props) ?? outerSrc);
const playbackCoreRef = useRef<PlaybackCore | undefined>(undefined);
const innerMediaElRef = useRef<HTMLVideoElement>(null);
Expand All @@ -55,9 +56,11 @@ const MuxVideo = React.forwardRef<HTMLVideoElement | undefined, Partial<Props>>(

useEffect(() => {
const propsWithState = {
// NOTE: Applying playerInitTime first as a simple way of overriding it if/when folks update
// the value via props after initial load (e.g. when swapping src)
playerInitTime,
...props,
src,
playerInitTime,
playerSoftwareName,
playerSoftwareVersion,
autoplay: autoPlay,
Expand Down
2 changes: 1 addition & 1 deletion packages/mux-video/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
"@typescript-eslint/parser": "^8.3.0",
"@web/dev-server-esbuild": "^1.0.2",
"@web/dev-server-import-maps": "^0.2.1",
"@web/test-runner": "^0.18.2",
"@web/test-runner": "^0.19.0",
"downlevel-dts": "^0.11.0",
"esbuild": "^0.19.8",
"eslint": "^9.9.1",
Expand Down
30 changes: 25 additions & 5 deletions packages/mux-video/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export const Attributes = {
PLAYBACK_ID: 'playback-id',
PLAYER_SOFTWARE_NAME: 'player-software-name',
PLAYER_SOFTWARE_VERSION: 'player-software-version',
PLAYER_INIT_TIME: 'player-init-time',
PREFER_CMCD: 'prefer-cmcd',
PREFER_PLAYBACK: 'prefer-playback',
START_TIME: 'start-time',
Expand Down Expand Up @@ -101,7 +102,7 @@ class MuxVideoBaseElement extends CustomVideoElement implements Partial<MuxMedia

#core?: PlaybackCore;
#loadRequested?: Promise<void> | null;
#playerInitTime: number;
#defaultPlayerInitTime: number;
#metadata: Readonly<Metadata> = {};
#tokens: Tokens = {};
#_hlsConfig?: Partial<HlsConfig>;
Expand All @@ -111,7 +112,7 @@ class MuxVideoBaseElement extends CustomVideoElement implements Partial<MuxMedia

constructor() {
super();
this.#playerInitTime = generatePlayerInitTime();
this.#defaultPlayerInitTime = generatePlayerInitTime();
}

get preferCmcd() {
Expand All @@ -130,7 +131,19 @@ class MuxVideoBaseElement extends CustomVideoElement implements Partial<MuxMedia
}

get playerInitTime() {
return this.#playerInitTime;
if (!this.hasAttribute(Attributes.PLAYER_INIT_TIME)) return this.#defaultPlayerInitTime;
return +(this.getAttribute(Attributes.PLAYER_INIT_TIME) as string) as number;
}

set playerInitTime(val) {
// don't cause an infinite loop and avoid change event dispatching
if (val == this.playerInitTime) return;

if (val == null) {
this.removeAttribute(Attributes.PLAYER_INIT_TIME);
} else {
this.setAttribute(Attributes.PLAYER_INIT_TIME, `${+val}`);
}
}

get playerSoftwareName() {
Expand Down Expand Up @@ -593,7 +606,7 @@ class MuxVideoBaseElement extends CustomVideoElement implements Partial<MuxMedia

set liveEdgeOffset(val: number | undefined) {
// don't cause an infinite loop and avoid change event dispatching
if (val == this.targetLiveWindow) return;
if (val == this.liveEdgeOffset) return;

if (val == null) {
this.removeAttribute(Attributes.LIVE_EDGE_OFFSET);
Expand Down Expand Up @@ -855,6 +868,13 @@ if (!globalThis.customElements.get('mux-video')) {
globalThis.MuxVideoElement = MuxVideoElement;
}

export { PlaybackEngine, PlaybackEngine as Hls, ExtensionMimeTypeMap as MimeTypes, MediaError, VideoEvents };
export {
PlaybackEngine,
PlaybackEngine as Hls,
ExtensionMimeTypeMap as MimeTypes,
MediaError,
VideoEvents,
generatePlayerInitTime,
};

export default MuxVideoElement;
Loading
Loading