Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions examples/nextjs-with-typescript/components/renderers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,62 @@ export const BooleanRenderer = ({
);
};

export const OptionalBooleanRenderer = ({
name,
value,
label,
onChange,
formatter = DefaultEnumFormatter
}: {
name: string;
value: boolean | undefined;
label?: string;
removeFalse?: boolean;
onChange: (obj: any) => void;
formatter?: (enumValue: boolean) => ReactNode;
}) => {
const labelStr = label ?? toWordsFromKeyName(name);
const values = [true, false];
return (
<div>
<label htmlFor={`${name}-control`}>
{labelStr} (<code>{name}</code>)
</label>
<div>
<input
id={`${name}-none-control`}
type="radio"
onChange={() => {

console.log("Selecting value:", undefined, toChangeObject(name, undefined));
onChange(toChangeObject(name, undefined))}}
value=""
checked={value === undefined}
/>
<label htmlFor={`${name}-none-control`}>None</label>
{values.map((enumValue, i) => {
return (
<Fragment key={`${name}-${enumValue}`}>
<input
id={`${name}-${enumValue}-control`}
type="radio"
onChange={() => {
const changeValue = enumValue;
console.log("Selecting value:", changeValue, toChangeObject(name, changeValue));
onChange(toChangeObject(name, changeValue));
}}
value={enumValue.toString()}
checked={value === enumValue}
/>
<label htmlFor={`${name}-${enumValue}-control`}>{formatter(enumValue)}</label>
</Fragment>
);
})}
</div>
</div>
);
};

export const NumberRenderer = ({
name,
value,
Expand Down
5 changes: 5 additions & 0 deletions examples/nextjs-with-typescript/pages/MuxPlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,11 @@ function MuxPlayerPage({ location }: Props) {
min={0}
step={1}
/>
<BooleanRenderer
value={state.capLevelToPlayerSize}
name="capLevelToPlayerSize"
onChange={genericOnChange}
></BooleanRenderer>
</div>
</main>
</>
Expand Down
27 changes: 25 additions & 2 deletions examples/nextjs-with-typescript/pages/mux-video-react.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import Head from 'next/head';
import { useRef, useState } from "react";
import MuxVideo from "@mux/mux-video/react";
import MuxPlayerElement from '@mux/mux-player';
import { EnumRenderer, OptionalBooleanRenderer } from '../components/renderers';
import MuxVideoElement from '@mux/mux-video';

const INITIAL_AUTOPLAY = false;
const INITIAL_MUTED = false;
const INITIAL_CAP_LEVEL_TO_PLAYER_SIZE = undefined;
const INITIAL_PREFER_PLAYBACK = undefined;

function MuxVideoPage() {
const mediaElRef = useRef(null);
const mediaElRef = useRef<MuxVideoElement>(null);
const [autoplay, setAutoplay] = useState<"muted" | boolean>(INITIAL_AUTOPLAY);
const [muted, setMuted] = useState(INITIAL_MUTED);
const [preferPlayback, setPreferPlayback] = useState<MuxPlayerElement["preferPlayback"]>(INITIAL_PREFER_PLAYBACK);
const [capLevelToPlayerSize, setCapLevelToPlayerSize] = useState(INITIAL_CAP_LEVEL_TO_PLAYER_SIZE);
const [paused, setPaused] = useState<boolean | undefined>(true);

return (
Expand All @@ -32,12 +39,13 @@ function MuxVideoPage() {
// }}
// envKey="mux-data-env-key"
controls
capLevelToPlayerSize={capLevelToPlayerSize}
autoplay={autoplay}
muted={muted}
maxResolution="2160p"
minResolution="540p"
renditionOrder="desc"
preferPlayback="native"
preferPlayback={preferPlayback}
onPlay={() => {
setPaused(false);
}}
Expand All @@ -47,6 +55,10 @@ function MuxVideoPage() {
/>

<div className="options">
<button onClick={() => {
if (!mediaElRef.current) return;
mediaElRef.current.load();
}}>Reload</button>
<div>
<label htmlFor="paused-control">Paused</label>
<input
Expand Down Expand Up @@ -74,6 +86,17 @@ function MuxVideoPage() {
checked={muted}
/>
</div>
<EnumRenderer
value={preferPlayback}
name="preferPlayback"
onChange={({ preferPlayback }) => setPreferPlayback(preferPlayback as MuxPlayerElement["preferPlayback"])}
values={['mse', 'native']}
/>
<OptionalBooleanRenderer
value={capLevelToPlayerSize}
name="capLevelToPlayerSize"
onChange={({ capLevelToPlayerSize }) => setCapLevelToPlayerSize(capLevelToPlayerSize)}
/>
</div>
</>
);
Expand Down
1 change: 1 addition & 0 deletions packages/mux-player-react/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ export type MuxPlayerProps = {
theme?: string;
themeProps?: { [k: string]: any };
fullscreenElement?: string;
capLevelToPlayerSize?: boolean;
onAbort?: GenericEventListener<MuxPlayerElementEventMap['abort']>;
onCanPlay?: GenericEventListener<MuxPlayerElementEventMap['canplay']>;
onCanPlayThrough?: GenericEventListener<MuxPlayerElementEventMap['canplaythrough']>;
Expand Down
24 changes: 24 additions & 0 deletions packages/mux-player/src/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ function getProps(el: MuxPlayerElement, state?: any): MuxTemplateProps {
proudlyDisplayMuxBadge: el.hasAttribute(PlayerAttributes.PROUDLY_DISPLAY_MUX_BADGE),
castReceiver: el.castReceiver,
disablePseudoEnded: el.hasAttribute(PlayerAttributes.DISABLE_PSEUDO_ENDED),
disableCapLevelToPlayerSize: el.disableCapLevelToPlayerSize,
...state,
// NOTE: since the attribute value is used as the "source of truth" for the property getter,
// moving this below the `...state` spread so it resolves to the default value when unset (CJP)
Expand Down Expand Up @@ -1883,6 +1884,29 @@ class MuxPlayerElement extends VideoApiElement implements IMuxPlayerElement {
this.setAttribute(PlayerAttributes.PROUDLY_DISPLAY_MUX_BADGE, '');
}
}

get capLevelToPlayerSize(): boolean | undefined {
if (this._hls) {
return this._hls.capLevelToPlayerSize;
}
return this._hlsConfig?.capLevelToPlayerSize;
}

set capLevelToPlayerSize(val: boolean | undefined) {
this._hlsConfig = { ...this._hlsConfig, capLevelToPlayerSize: val };
}

get disableCapLevelToPlayerSize(): boolean {
return this.hasAttribute(MuxVideoAttributes.DISABLE_CAP_LEVEL_TO_PLAYER_SIZE);
}

set disableCapLevelToPlayerSize(val: boolean | undefined) {
if (!val) {
this.removeAttribute(MuxVideoAttributes.DISABLE_CAP_LEVEL_TO_PLAYER_SIZE);
} else {
this.setAttribute(MuxVideoAttributes.DISABLE_CAP_LEVEL_TO_PLAYER_SIZE, '');
}
}
}

export function getVideoAttribute(el: MuxPlayerElement, name: string) {
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 @@ -141,6 +141,7 @@ export const content = (props: MuxTemplateProps) => html`
exportparts="video"
disable-pseudo-ended="${props.disablePseudoEnded ?? false}"
max-auto-resolution="${props.maxAutoResolution ?? false}"
cap-level-to-player-size="${props.capLevelToPlayerSize ?? false}"
>
${props.storyboard
? html`<track label="thumbnails" default kind="metadata" src="${props.storyboard}" />`
Expand Down
1 change: 1 addition & 0 deletions packages/mux-player/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export type MuxTemplateProps = Partial<MuxPlayerProps> & {
/** Allow playback with ad blocker */
allowAdBlocker?: boolean;
disablePseudoEnded?: boolean;
capLevelToPlayerSize?: boolean;
};

export type DialogOptions = {
Expand Down
1 change: 1 addition & 0 deletions packages/mux-video/src/ads/react.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const ReactPropToAttrNameMap: Record<string, string> = {
playsInline: 'playsinline',
disablePictureInPicture: 'disablepictureinpicture',
disableRemotePlayback: 'disableremoteplayback',
capLevelToPlayerSize: 'cap-level-to-player-size',
};

function toAttributeName(propName: string) {
Expand Down
33 changes: 33 additions & 0 deletions packages/mux-video/src/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export const Attributes = {
LIVE_EDGE_OFFSET: 'live-edge-offset',
TYPE: 'type',
LOGO: 'logo',
DISABLE_CAP_LEVEL_TO_PLAYER_SIZE: 'disable-cap-level-to-player-size',
} as const;

const AttributeNameValues = Object.values(Attributes);
Expand Down Expand Up @@ -516,6 +517,29 @@ export class MuxVideoBaseElement extends CustomVideoElement implements IMuxVideo
}
}

get capLevelToPlayerSize(): boolean | undefined {
if (this._hls) {
return this._hls.capLevelToPlayerSize;
}
return this._hlsConfig?.capLevelToPlayerSize;
}

set capLevelToPlayerSize(val: boolean | undefined) {
this._hlsConfig = { ...this._hlsConfig, capLevelToPlayerSize: val };
}

get disableCapLevelToPlayerSize(): boolean {
return this.hasAttribute(Attributes.DISABLE_CAP_LEVEL_TO_PLAYER_SIZE);
}

set disableCapLevelToPlayerSize(val: boolean | undefined) {
if (!val) {
this.removeAttribute(Attributes.DISABLE_CAP_LEVEL_TO_PLAYER_SIZE);
} else {
this.setAttribute(Attributes.DISABLE_CAP_LEVEL_TO_PLAYER_SIZE, '');
}
}

get drmToken() {
return this.getAttribute(Attributes.DRM_TOKEN) ?? undefined;
}
Expand Down Expand Up @@ -900,6 +924,15 @@ export class MuxVideoBaseElement extends CustomVideoElement implements IMuxVideo
}
break;
}
/*case Attributes.CAP_LEVEL_TO_PLAYER_SIZE: {
if (newValue == null || newValue !== oldValue) {
const capLevelToPlayerSize = this.capLevelToPlayerSize;
if (this._hls) {
this._hls.config.capLevelToPlayerSize = capLevelToPlayerSize ?? false;
}
}
break;
}*/
}
}

Expand Down
1 change: 1 addition & 0 deletions packages/mux-video/src/react.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const ReactPropToAttrNameMap: Record<string, string> = {
playsInline: 'playsinline',
disablePictureInPicture: 'disablepictureinpicture',
disableRemotePlayback: 'disableremoteplayback',
capLevelToPlayerSize: 'cap-level-to-player-size',
};

function toAttributeName(propName: string) {
Expand Down
32 changes: 27 additions & 5 deletions packages/playback-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { ValueOf, PlaybackCore, MuxMediaProps, MuxMediaPropsInternal, MuxMe
import mux, { ErrorEvent } from 'mux-embed';
import Hls from './hls';
import type { HlsInterface } from './hls';
import type { ErrorData, HlsConfig } from 'hls.js';
import type { CapLevelController, ErrorData, HlsConfig } from 'hls.js';
import { MediaError, MuxErrorCategory, MuxErrorCode, errorCategoryToTokenNameOrPrefix } from './errors';
import { setupAutoplay } from './autoplay';
import { setupPreload } from './preload';
Expand Down Expand Up @@ -705,6 +705,7 @@ export const setupHls = (
| 'tokens'
| 'drmTypeCb'
| 'maxAutoResolution'
| 'disableCapLevelToPlayerSize'
>
>,
mediaEl: HTMLMediaElement
Expand All @@ -728,7 +729,6 @@ export const setupHls = (
backBufferLength: 30,
renderTextTracksNatively: false,
liveDurationInfinity: true,
capLevelToPlayerSize: true,
capLevelOnFPSDrop: true,
};
const streamTypeConfig = getStreamTypeConfig(streamType);
Expand All @@ -743,8 +743,24 @@ export const setupHls = (
}
: undefined;

const capLevelControllerObj =
_hlsConfig.capLevelToPlayerSize == null ? { capLevelController: MinCapLevelController } : {};
const capLevelControllerObj: {
capLevelController?: typeof CapLevelController;
capLevelToPlayerSize?: boolean;
} = {};

// If capLevelToPlayerSize is not explicitly set we enable MinCapLevelController
if (_hlsConfig.capLevelToPlayerSize == null) {
capLevelControllerObj.capLevelController = MinCapLevelController;
capLevelControllerObj.capLevelToPlayerSize = true;
} else {
capLevelControllerObj.capLevelController = undefined;
capLevelControllerObj.capLevelToPlayerSize = _hlsConfig.capLevelToPlayerSize;
}
if (props.disableCapLevelToPlayerSize) {
capLevelControllerObj.capLevelController = undefined;
capLevelControllerObj.capLevelToPlayerSize = false;
}


const hls = new Hls({
// Kind of like preload metadata, but causes spinner.
Expand All @@ -763,13 +779,19 @@ export const setupHls = (

xhr.open('GET', urlObj);
},
...capLevelControllerObj,
...defaultConfig,
...capLevelControllerObj,
...streamTypeConfig,
...drmConfig,
..._hlsConfig,
}) as HlsInterface;

console.log("capLevelToPlayerSize summary", {
hlsConfigCapLevelToPlayerSize: _hlsConfig.capLevelToPlayerSize,
disableCapLevelToPlayerSize: props.disableCapLevelToPlayerSize,
capLevelControllerObj: capLevelControllerObj,
hlsCapLevelToPlayerSize: hls.capLevelToPlayerSize,
});
if (capLevelControllerObj.capLevelController === MinCapLevelController) {
if (maxAutoResolution !== undefined) {
MinCapLevelController.setMaxAutoResolution(hls, maxAutoResolution);
Expand Down
2 changes: 2 additions & 0 deletions packages/playback-core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ export type MuxMediaPropTypes = {
_hlsConfig?: Partial<HlsConfig>;
autoPlay?: Autoplay;
autoplay?: Autoplay;
capLevelToPlayerSize?: boolean;
disableCapLevelToPlayerSize?: boolean;
beaconCollectionDomain: Options['beaconCollectionDomain'];
customDomain: string;
debug: Options['debug'] & Hls['config']['debug'];
Expand Down
Loading