Skip to content

Commit

Permalink
feat: basic drm support (#905)
Browse files Browse the repository at this point in the history
Implementing basic DRM support.
  • Loading branch information
cjpillsbury authored Jun 4, 2024
1 parent 845493b commit 79acc9d
Show file tree
Hide file tree
Showing 14 changed files with 673 additions and 406 deletions.
1 change: 1 addition & 0 deletions examples/nextjs-with-typescript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"private": true,
"scripts": {
"dev": "next dev",
"dev:secure": "next dev --experimental-https",
"build": "next build",
"start": "next start",
"lint": "next lint"
Expand Down
3 changes: 1 addition & 2 deletions packages/mux-player-react/REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,13 @@
| `programStartTime` | `number` | Apply PDT-based [instant clips](https://docs.mux.com/guides/create-instant-clips) to the beginning of the media stream. | N/A |
| `programEndTime` | `number` | Apply PDT-based [instant clips](https://docs.mux.com/guides/create-instant-clips) to the end of the media stream. | N/A |
| `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; }` | `undefined` |
| `tokens` | `object`\* | An object for setting all signed URL tokens with the signature `{ playback?: string; thumbnail?: string; storyboard?: string; drm?: string; }` | `undefined` |
| `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
// NEW STREAM TYPE VALUES
| `streamType` | `"on-demand" \| "live" \| "unknown"` | The type of stream associated with your Mux Asset. Used along with `targetLiveWindow` to determine what UI/controls to show. | (inferred from `playbackId`, otherwise `"unknown"`) |
| `preferCmcd` | `"query" \| "header"` | Preference for how CMCD data is sent provided in Mux Video requests. Defaults to query params for performance. | `"query"` |
| `experimentalCmcd` | `boolean` | Enables CMCD usage for media asset requests (playlists, segments). | `false` |
| `playsInline` | `boolean` | Identical to the native `playsInline` property (property equivalent to [`<video playsinline/>` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#attr-playsinline) | `false` |
| `src` | `string` (URL) | Full URL string for the media asset. Typically derived from the `playbackId` | `undefined` |
-->
Expand Down
4 changes: 3 additions & 1 deletion packages/mux-player/REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
| `playback-token` | `string` | The playback token for signing the `src` URL. | N/A |
| `thumbnail-token` | `string` | The thumbnail token for signing the `poster` URL. | N/A |
| `storyboard-token` | `string` | The storyboard token for signing the storyboard URL. | N/A |
| `drm-token` | `string` | The token for signing [DRM](https://www.mux.com/beta/drm) license and related URLs. | N/A |
| `storyboard-src` | `string` (URL) pointing to a [.vtt](https://image.mux.com/FuJSYrK0014ec2LPnm11bzC2MAySAQPqA/storyboard.vtt) file | Full URL string for the storyboard asset. Typically derived from the `playbackId`, setting this attribute will override the derived storyboard. | `undefined` |
| `thumbnail-time` | `number` (seconds) | [Time offset](https://docs.mux.com/guides/video/get-images-from-a-video#thumbnail-query-string-parameters) for the default `poster` image based on your `playback-id`. If no `thumbnail-time` is specified, `start-time` will be used by default. NOTE: This feature currently cannot be used with `thumbnail-token`. | `0` |
| `audio` | `boolean` | Indicate that you want an "audio only" UI/chrome. This may be used for audio-only assets or audio+video assets. | `false` |
Expand Down Expand Up @@ -141,8 +142,9 @@
| `playbackToken` | `string` | The playback token for signing the `src` URL. | `undefined` |
| `thumbnailToken` | `string` | The thumbnail token for signing the `poster` URL. | `undefined` |
| `storyboardToken` | `string` | The storyboard token for signing the storyboard URL. | `undefined` |
| `drmToken` | `string` | The token for signing [DRM](https://www.mux.com/beta/drm) license and related URLs. | `undefined` |
| `storyboardSrc` | `string` (URL) | Full URL string for the storyboard asset. Setting this will override the storyboard URL derived from the playback ID. | `undefined` |
| `tokens` | `object`\* | An object for setting all signed URL tokens with the signature `{ playback: string; thumbnail: string; storyboard: string; }`. If any `*token` properties or `*-token` attributes are set, they will take precedence. | `undefined` |
| `tokens` | `object`\* | An object for setting all signed URL tokens with the signature `{ playback?: string; thumbnail?: string; storyboard?: string; drm?: string; }`. If any `*token` properties or `*-token` attributes are set, they will take precedence. | `undefined` |
| `textTracks` | [`TextTrackList`](https://developer.mozilla.org/en-US/docs/Web/API/TextTrackList) | Identical to the [native `textTracks` property](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/textTracks) | (empty `TextTrackList` instance) |
| `cuePoints` <sub><sup>Read only</sup></sub> | `Array<{ startTime: number; endTime?: number, value: any; }>` | The array of CuePoints for the current media, added via `addCuePoints(cuePoints)`. | `[]` |
| `chapters` <sub><sup>Read only</sup></sub> | `Array<{ startTime: number; endTime?: number, value: string; }>` | The array of Chapters for the current media, added via `addChapters(chapters)`. | `[]` |
Expand Down
18 changes: 18 additions & 0 deletions packages/mux-player/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const DefaultThemeName = 'gerwig';
export { MediaError };
export type Tokens = {
playback?: string;
drm?: string;
thumbnail?: string;
storyboard?: string;
};
Expand All @@ -63,6 +64,7 @@ const PlayerAttributes = {
PLAYBACK_TOKEN: 'playback-token',
THUMBNAIL_TOKEN: 'thumbnail-token',
STORYBOARD_TOKEN: 'storyboard-token',
DRM_TOKEN: 'drm-token',
STORYBOARD_SRC: 'storyboard-src',
THUMBNAIL_TIME: 'thumbnail-time',
AUDIO: 'audio',
Expand Down Expand Up @@ -1570,11 +1572,13 @@ class MuxPlayerElement extends VideoApiElement implements MuxPlayerElement {
*/
get tokens(): Tokens {
const playback = this.getAttribute(PlayerAttributes.PLAYBACK_TOKEN);
const drm = this.getAttribute(PlayerAttributes.DRM_TOKEN);
const thumbnail = this.getAttribute(PlayerAttributes.THUMBNAIL_TOKEN);
const storyboard = this.getAttribute(PlayerAttributes.STORYBOARD_TOKEN);
return {
...this.#tokens,
...(playback != null ? { playback } : {}),
...(drm != null ? { drm } : {}),
...(thumbnail != null ? { thumbnail } : {}),
...(storyboard != null ? { storyboard } : {}),
};
Expand All @@ -1601,6 +1605,20 @@ class MuxPlayerElement extends VideoApiElement implements MuxPlayerElement {
this.setAttribute(PlayerAttributes.PLAYBACK_TOKEN, `${val}`);
}

/**
* Get the playback token for signing the src URL.
*/
get drmToken() {
return this.getAttribute(PlayerAttributes.DRM_TOKEN) ?? undefined;
}

/**
* Set the playback token for signing the src URL.
*/
set drmToken(val) {
this.setAttribute(PlayerAttributes.DRM_TOKEN, `${val}`);
}

/**
* Get the thumbnail token for signing the poster URL.
*/
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 @@ -120,6 +120,7 @@ export const content = (props: MuxTemplateProps) => html`
custom-domain="${props.customDomain ?? false}"
src="${!!props.src ? props.src : props.playbackId ? toMuxVideoURL(props) : false}"
cast-src="${!!props.src ? props.src : props.playbackId ? toMuxVideoURL(props) : false}"
drm-token="${props.tokens?.drm ?? false}"
exportparts="video"
>
${props.storyboard
Expand Down
1 change: 1 addition & 0 deletions packages/mux-player/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export type MuxTemplateProps = Partial<MuxPlayerProps> & {
extraSourceParams?: Record<string, any>;
tokens: {
playback?: string;
drm?: string;
thumbnail?: string;
storyboard?: string;
};
Expand Down
55 changes: 55 additions & 0 deletions packages/mux-player/test/player.pdt.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { fixture, assert, nextFrame } from '@open-wc/testing';
import '../src/index.ts';

// Media Chrome uses a ResizeObserver which ends up throwing in Firefox and Safari in some cases
// so we want to catch those. It is supposedly not a blocker if this error is thrown.
// Safari also has some weird script error being thrown, so, we want to catch it to.
// This unblocks a bunch of tests from running properly.
const windowErrorHandler = (e) => {
if (
e.message === 'ResizeObserver loop completed with undelivered notifications.' ||
e.message === 'ResizeObserver loop limit exceeded' ||
e.message === 'Script error.'
) {
e.stopPropagation();
e.preventDefault();
e.stopImmediatePropagation();
} else {
console.log('error', e);
}
};
window.addEventListener('error', windowErrorHandler);

describe('Feature: currentPdt and getStartDate', async () => {
it('currentPdt and getStartDate work as expected', async function () {
this.timeout(5000);

const player = await fixture(`<mux-player
env-key="ilc02s65tkrc2mk69b7q2qdkf"
stream-type="on-demand"
prefer-playback="mse"
muted
title="A title"
preload="auto"
></mux-player>`);

player.addEventListener('loadstart', async function () {
player.currentTime = 60;

await nextFrame();

const currentPdt = player.currentPdt;
const startDate = player.getStartDate();

assert.equal(
startDate.getTime(),
currentPdt.getTime() - player.currentTime * 1000,
'currentPdt should be 60 seconds greater than getStartDate'
);
});

await nextFrame();

player.playbackId = 'UgKrPYAnjMjP6oMF4Kcs1gWVhtgYDR02EHQGnj022X1Xo';
});
});
Loading

0 comments on commit 79acc9d

Please sign in to comment.