PRESTOplay Media Player Package

Table of Contents

1. Preface / Introduction

a. Background and Purpose

This package provides a customizable, modular web-based media player built on top of PRESTOplay. It supports advanced features such as DRM, adaptive streaming (DASH, HLS, Smooth), and robust subtitle and audio-only handling. The code is designed to quickly integrate secure video playback into their web applications, with options for custom controls and extensibility.

b. Scope and Learning Objectives


2. Environment and Prerequisites

a. Programming Language, Libraries, and Frameworks

b. Execution Environment

c. Installation and Setup

  1. Download the zipped package at: https://dr.orca.jp/PRESTOplay-drm-player/{uploaded-date}/prestoplay-package-zipped
  2. Unzipped the package and run:
    npm run build
    npm link
  3. Then navigate to your frontend project source, use this command to install the package:
    npm link prestoplay-drm-player

3. Overview of the Code

a. Final Output

The final product is a JS package that initializes a video player that supports:

b. Directory Structure

prestoplay-package/
  ├── demo.html                # Demo page for testing the player
  ├── src/
  │   ├── index.js             # Main player logic and class
  │   ├── custom-controls.js   # Custom UI controls logic
  │   ├── drm-config.js        # DRM configuration templates
  │   ├── audio-only-handler.js# Audio-only content handling
  │   ├── subtitle-handler.js  # Subtitle detection/handling logic
  │   └── styles.css           # Player and control styles
  ├── package.json             # Project metadata and dependencies
  ├── webpack.config.js        # Webpack build configuration
  └── README.md                # Project documentation

File Roles:


4. Step-by-Step Code Explanation

4.1. Player Initialization

Purpose:

Create and configure a PRESTOplay player instance, attach it to the DOM, and set up controls.

Example Initialization:
const player = new PrestoPlayDRMPlayer({
  containerId: "video-container", // (required) id of the container div
  source: "https://example.com/video.mpd", // (required) video source URL
  prestoplayCred: {                // (required) DRM credentials
    license: "",   // (required)
    viewerId: "" // (required)
  },
  width: 960,                     // (optional) video width
  height: 540,                    // (optional) video height
  isDRM: true,                    // (optional) enable DRM
  drmConfig: {                    // (optional) DRM config object (for User Authorization Callback Approach)
    env: "DRMtoday_STAGING",      // (optional) DRM environment, "DRMtoday" (Production) or "DRMtoday_STAGING" (Staging)
    customData: {
      userId: "rental1",
      sessionId: "p0",            // (optional) sessionId to validate user's active subscription
      merchant: "organizationApiName",
      assetId: "Widevine-Test"    // (optional) assetId of license requested content
    }
  },
  drmtoday: {                    // (optional) DRM config object (for Upfront Authorization Token Approach)
    userId: "rental1",
    sessionId: "p0",
    merchant: "organizationApiName",
    environment: "DRMtoday_STAGING",
    authToken: "MY_AUTHORIZATION_TOKEN" // (optional) pre-generated authorization token to validate user's active subscription
  },
  controls: false,                // (optional) use built-in controls
  autoplay: false,                // (optional)
  loop: false,                    // (optional)
  muted: false                    // (optional)
});
Required Parameters: Optional Parameters: Code Snippet (Class):
class PrestoPlayDRMPlayer {
  constructor(options = {}) {
    if (!options.containerId) throw new Error("containerId is required");
    if (!options.source) throw new Error("source is required");
    if (!options.prestoplayCred?.license && !options.prestoplayCred?.viewerId)
      throw new Error("license and viewerId is required to initialize a PRESTOplay player");
    // ...
  }
}
About PRESTOplay License and Merchant:
this.player = new clpp.Player(this.video, this.options.prestoplayCred);
Explanation: Pitfall:

4.2. DRM and Source Loading

Purpose:

Configure DRM and load the video source.

Code Snippet:
await this.player.load({
  source: this.options.source,
  autoplay: this.options.autoplay,
  loop: this.options.loop,
  muted: this.options.muted,
  drm: this.options.isDRM ? this.options.drmConfig : undefined,
});
Explanation: Pitfall:

4.3. Custom Controls and Subtitles

Purpose:

Add custom controls and handle subtitle tracks.

Code Snippet:
import { createCustomControls } from "./custom-controls";
createCustomControls(this.player, this.video, this.options.containerId);
Explanation: Pitfall:

4.4. Audio-Only Content Handling

Purpose:

Detect and adjust UI for audio-only content.

Code Snippet:
import { checkAudioOnlyContent } from "./audio-only-handler";
checkAudioOnlyContent(this);
Explanation: Pitfall:

4.5. Subtitle Detection and Handling

Purpose:

Detect, enable, and manage subtitle tracks using a modular handler.

Code Snippet:
import { setupSubtitleDetection } from "./subtitle-handler";
setupSubtitleDetection(this);
Explanation: Pitfall:

5. Use of Visuals and Diagrams

5.1. User Authorization Callback Implementation

User Authorization Callback Flow
Authentication Flow:

5.2. Authorization Methods Comparison

Feature Upfront Authorization Token User Authorization Callback
Core Idea The backend server pre-authorizes the user and gives the player a "ticket" (the token) to present to DRMtoday. DRMtoday receives a request and asks the backend server in real-time, "Is this user allowed to watch this?"
Workflow One-way trip: Client -> The Backend Server -> Client -> DRMtoday Round trip: Client -> DRMtoday -> The Backend Server -> DRMtoday -> Client
Backend Responsibility Generate a secure, signed, and short-lived token before the license request is made. Implement a server endpoint that can receive a real-time callback from DRMtoday and respond instantly.
Complexity Simpler for the DRM provider (DRMtoday), but requires the backend server to handle token generation logic. More complex backend logic is required to handle the real-time callback, but it gives you more direct control.
Latency Potentially lower latency, as DRMtoday can issue the license immediately after validating the token without an extra network hop. Slightly higher latency due to the additional real-time callback from DRMtoday to the backend server.
Real-time Control Less real-time control. A user's rights are based on when the token was generated (tokens are valid for 10 minutes). Maximum real-time control. You can deny a license request the instant a user's subscription expires.
Best For Standard VOD playback, SPAs, and situations where you want to reduce the real-time load on the backend server. Live streaming, pay-per-view events, or systems where immediate, up-to-the-second authorization is critical.

6. Supplementary Notes and Advanced Topics

a. Better Design Practices

b. Advanced Considerations


7. Error Handling and Debugging Tips

a. Common Error Messages

b. Debugging Tools


For further questions or advanced customization, refer to the official PRESTOplay documentation or contact your system administrator.