# Universal Player: UI customization and configuration reference This guide describes the maintained SDK source for Web, Android/Android TV, iOS/iPadOS/tvOS, Samsung Tizen, Roku and native Amazon Vega. Use the version and checksum in your downloaded bundle's README and Console as the release identity. Opaque stock menus are included in Web 1.2.0-beta.7, Android SDK 1.0.0-beta.14 and Apple SDK 1.0.0-beta.10. Earlier downloaded binaries retain their behavior. OTT source changes require separate device qualification; the Samsung very-late-seek regression remains pending a physical-TV retest. ## Choose the appropriate customization level | Level | Use it for | Application responsibility | | --- | --- | --- | | Stock player and theme | Fast integration with the supplied controls | Supply authorized content, viewer login, lifecycle and a storage scope. | | Configured stock UI | Branding colors, layouts, visible controls, labels and timings | Use the supported fields below; test touch, keyboard, remote and accessibility. | | Your own UI | A different layout or application-specific controls | Retain the SDK playback owner, connect supported methods/events and implement focus, captions, loading/error states and disposal. | Presentation changes do not grant content access. Your backend authenticates the viewer, checks each Content ID and supplies a playback session. The DRM License Token, CDM, server policy and available media determine actual playback rights. Keep Site Key, Access Key, provider credentials and content keys on the server. ## Documentation map 1. **README / CUSTOMER-INTEGRATION.md:** install the exact bundle, build its supplied sample, replace demo login with your application's authentication. 2. **This reference:** configure presentation, choose stock or custom controls, understand parameter defaults and precedence. 3. **PLAYER-EXPERIENCE.md / COMMERCIAL-NATIVE.md / COMMERCIAL-OTT.md:** platform initializer, playlist mutation and event examples. 4. **PLAYER-CONTRACT.md / OTT-SERVER-CONFIGURATION.md:** backend responses, capability negotiation, UI override allowlists, quality and ads. 5. **PLAYER-CAPABILITIES.md / PLAYER-CONSISTENCY.md:** implemented API support, platform differences and qualification limits. 6. **OFFLINE_INTEGRATION.md, platform README and qualification notes:** complete download ownership, errors, device/OS evidence and production acceptance. The public platform guides remain at `https://docs.drm-x.com/sdk/web`, `/sdk/android`, `/sdk/apple`, `/sdk/tizen`, `/sdk/roku` and `/sdk/firetv`. These documents do not introduce a new menu, wizard or player activation step. ## Configuration order and ownership The shared endpoint resolves SDK defaults, common server presentation and platform-specific server presentation. App UI overrides apply only where the response's `appUiOverrideAllowlist` permits them. An omitted allowlist has legacy permissive presentation semantics; use an explicit list, or `[]` to lock it down. Viewer appearance/track preferences can override initial defaults. Supported features, real track inventories and authorization always limit the final result. Keep viewer storage scoped to the endpoint, tenant and signed-in viewer. Native apps can use `DrmXStorageScope.create`; do not use a shared namespace for unrelated viewers. Endpoint/account changes require disposing the previous playback owner. UI changes alone must not create another license session or replace the video. Tizen/Vega validate runtime UI patches before saving them, including fields a current server allowlist does not apply. A rejected patch leaves the last usable configuration intact for later server updates. ### Opaque popup policy DRM-X stock settings, language/quality menus and other owned popup panels use fully opaque surfaces. Midnight, Light and Graphite preserve their palette. Custom panel colors retain their RGB value, with opaque alpha for stock menus. The legacy `menuOpacity` input still accepts finite values from `0.5` to `1` for compatibility; it no longer enables transparent popup backgrounds. New configuration should omit it or use `1`. Old server configurations cannot make the updated stock menu translucent. Invalid legacy values are still rejected. This is separate from caption/watermark opacity, transport scrims, shadows and the operating system's own media/dialog appearance. Custom UI authors must keep their own menus legible. The SDK does not change device accessibility settings. ## Stock UI parameter reference The names below use shared JSON/Web spelling. Kotlin constructor properties use the same names where implemented. Swift uses native enums and `Set`; Roku uses associative arrays and SceneGraph fields. Unsupported fields must not be inferred from another platform's appearance. | Field | Values / validation | Default and application | | --- | --- | --- | | `style` | `youtube`, `universal`; native enums `YouTube`/`Universal`, `.youtube`/`.universal` | Web/shared OTT: `youtube`; Android/Apple native UI: Universal. | | `theme` | Midnight, Light, Graphite; Web/OTT JSON uses lowercase | Midnight. Android/Apple additionally accept native theme tokens. | | `colors` | `background`, `panel`, `text`, `secondary`, `accent`; six-digit `#RRGGBB` for Web/OTT | Override the selected palette. Apple remote colors currently consume background/panel/text/accent; use native theme tokens for native colors. | | `menuOpacity` | Legacy finite `0.5–1`; stock render is always opaque | `1`; omit in new integrations. | | `playlistVisible` | Boolean | `true`; changes presentation, not playlist contents or permission. | | `navigationVisible` | Boolean | `true`; show applicable Previous/Next controls. | | `allowShuffle` | Boolean | `true` in catalog UI; a single-video preset can disable it. | | `allowReordering` | Boolean | Web/Android/Apple/Roku support supplied reorder controls. Tizen/Vega hosts need their own reorder UI. | | `controlsVisible` | Boolean | `true`; provide accessible replacement controls before hiding the stock ones. | | `hiddenControls` | IDs for controls implemented by that platform | Empty; unsupported controls are not created. | | `hiddenMenuItems` | IDs for implemented menu entries | Empty; hiding an entry does not disable its underlying API. | | `seekStepSeconds` | Integer `1–120` | `10`; live/seekable range still applies. | | `controlsHideDelaySeconds` | Integer `0–60` | `5`; zero disables auto-hide. Paused/open-menu/accessibility behavior takes precedence. | | `nextCountdownSeconds` | Web/Android/Apple integer `0–30` | Web/Android: `0`; Apple UI: `5`. Repeat All advances immediately; Tizen/Vega/Roku do not gain a countdown from this field. | | `labelOverrides` | English fallback label → application text | Empty. Web/Android/Apple support stock labels; check OTT renderer support rather than assuming every label is replaceable. | | `customActions` | Unique IDs with labels; Web/Android/Apple maximum 20 | Empty; wire the platform callback. Not a portable OTT button extension. | | `textScale` | Android/Apple finite `0.8–1.5` | `1`; interface text only, independent of captions and system font settings. | | `captionStyle` | See the caption table below | Initial defaults only; supported saved viewer choices take precedence. | | `menuLayout` | Tizen/Vega/Roku: `overlay`, `side-preview` | `overlay`; video/session stays mounted. Android TV has its own `television.settingsPresentation` enum. | Common stock control IDs include `play`, `captions`, `settings`, `fullscreen`, `rewind`, `forward`, `previous`, `next`, `timeline`, `playlist`. Web also exposes `pip`, `theater`, `mute`; availability differs on native engines. Common menu IDs include `quality`, `audio`, `captions`, `speed`, `sleep`, `appearance`, `chapters`, `transcript`, `bookmarks`, `information`, `about`. Only implemented entries can appear. Use the platform declaration files for the exact public API. ### Initial playback values | Value | Native grouped / shared OTT behavior | | --- | --- | | `autoplay`, `autoNext`, `shuffle` | `false`. Explicit Play and browser/OS autoplay rules still apply. | | `repeat` / Apple `repeatMode` | Grouped configurations: off. Legacy Web/Android views and some demo apps may start Repeat All; choose explicitly when integrating. | | `audioLanguage`, `subtitleLanguage` | Native grouped audio default `en`, captions off; shared OTT defaults native selection (`null` / Roku empty string). Saved viewer choices may take precedence. | | `qualityHeight` | Auto (`null` / Roku `0`). Web/Android/Apple quality selection and OTT exact-height/ceiling behavior differ. Server/CDM/device limits always win. | | `rate` | Web/Android/Apple supported rates: 0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2. Live uses 1. No portable Tizen/Vega/Roku speed API is promised. | | `muted` | Native grouped default false. System audio policy/volume remains authoritative; not a shared OTT configuration promise. | | `resumePosition`, `rememberTracks` | Native preferences default true. Tizen/Vega stock controllers do not promise the same persistence as Android/Apple/Roku. | | `progressIntervalSeconds` | Native preference range `1–300`, default `10`. Client progress is advisory, never proof of entitlement or billing. | Ads, offline endpoints and branding entitlement are separate integrations. A quality preference is not the authorized maximum; a hidden Download control does not implement or disable persistent licenses. Endpoint-required ads and required watermarks are not removable through UI overrides. ### Caption values (independent from popup backgrounds) | Field | Accepted values | Default | | --- | --- | --- | | `fontFamily` | `sans-serif`, `serif`, `monospace` | `sans-serif` | | `fontScale` | 50, 75, 100, 125, 150, 175, 200 | 100 | | `fontColor`, `backgroundColor`, `windowColor` | Six-digit hex, supported palette in stock chooser | white / black / black | | `fontOpacity` | 25, 50, 75, 100 | 100 | | `backgroundOpacity` | 0, 25, 50, 75, 100 | 75 | | `windowOpacity` | 0, 25, 50, 75, 100 | 0 | | `edgeStyle` | `none`, `outline`, `shadow` | `outline` | System captions, native full-screen/PiP surfaces and bitmap captions can expose fewer styling options. Tizen needs its authorized external WebVTT integration; Roku's supported clear subtitle parser and device-specific limits remain in its README. Never invent a track or grant access because an initial language is set. ## Web example: configure the supplied component ```javascript await customElements.whenDefined('drmx-universal-player'); const player = document.querySelector('drmx-universal-player'); player.configureUi({ theme: 'graphite', colors: { accent: '#4d9fff', panel: '#202020' }, hiddenMenuItems: ['transcript'], seekStepSeconds: 15, controlsHideDelaySeconds: 5, labelOverrides: { Settings: 'Playback options' } }); ``` `configureUi` changes presentation without replacing playback. Use `start`, `stop`, track APIs and `attachControls` for a host video/custom control adapter. The Web declarations describe the adapter's required methods. Disconnect/remove the component and stop/release playback when its screen closes or the viewer signs out. Do not pass server credentials through element attributes or URLs. ## Android example: grouped initializer and native theme ```kotlin val scope = DrmXStorageScope.create(endpoint, tenantId, viewerId) val configuration = DrmXPlayerConfiguration.catalog().copy( ui = DrmXPlayerUiConfiguration( theme = DrmXPlayerTheme.Graphite.copy(accent = 0xFF4D9FFF.toInt()), seekStepSeconds = 15, hiddenMenuItems = setOf("transcript"), labelOverrides = mapOf("Settings" to "Playback options") ) ) val player = DrmXUniversalPlayer(view, endpoint, scope, configuration = configuration, authenticate = customerAuthenticationProvider) player.loadPlaylist(listOf(DrmXPlaylistItem(contentId, "Your video"))) // On the main thread: player.updateUi(nextUi). // Activity lifecycle: player.onStart(); player.onStop(); final disposal: player.close(). ``` `customerAuthenticationProvider` is your `DrmXAuthenticationProvider`, which supplies fresh viewer headers and honors cancellation. Protect the Activity with `DrmXPlayer.protectWindow(window)`. Use the complete starter sample for lifecycle, window insets and rotation. `DrmXPlayer`, its native Media3 surface and callbacks are available for your own controls; hiding stock controls is only presentation. ## Apple example: retain one model ```swift var configuration = DrmXPlayerConfiguration.catalog configuration.ui.theme = .graphite configuration.ui.seekStepSeconds = 15 configuration.ui.hiddenMenuItems = ["transcript"] configuration.ui.labelOverrides = ["Settings": "Playback options"] let model = try DrmXUniversalPlayer( endpoint: endpoint, playlist: DrmXPlaylist(items: items), configuration: configuration, storageNamespace: viewerScope, authenticate: freshViewerHeaders ) // Retain model in @StateObject or a coordinator, not in a recomputing body. DrmXUniversalPlayerView(model: model) ``` Call `try model.updateUi(nextUi)` on the main actor. UIKit hosts can use `DrmXPlayerViewController(model:)`. For a completely custom interface, use the model/lower-level `DrmXFairPlayPlayer` and retain its AVPlayer owner. Stop when leaving playback; `await model.close()` on final disposal/sign-out. iOS/iPadOS support the documented persistent-download integration; tvOS is streaming-only. ## OTT examples and limits Tizen/Vega controllers accept `configuration: { ui: {...}, playback: {...} }` and runtime `updateUi({...})`. Tizen's supplied view also exposes `window.DrmXPlayerUi.configure({...})`. A custom view must connect the controller to the platform's AVPlay or native Vega adapter and manage remote focus/Back. Roku hosts use `player.callFunc("configurePlayer", {ui: {...}, playback: {...}})`. Use the declared `DrmXPlayer` fields/callFuncs and SceneGraph native Video for custom controls. The stock `PlayerScene` supplies the menus and focus behavior. Configure viewer storage and the authenticated endpoint before selecting a title. Do not infer live, offline, casting, chapters, speed, advertising or accessibility support from a shared theme or API name. Consult capability inventory, runtime track state and the platform qualification report. Fire OS Android and native Vega are distinct integrations. There is no shipped native webOS/VIDAA adapter. ## Error handling and production checklist - Validate configuration before playback. Keep the previous usable UI when a runtime patch is invalid; do not catch an entitlement error and play clear media. - Handle expired login, denied content, unavailable tracks and network failures with actionable UI. Diagnostics must omit credentials, keys and license bytes. - Verify menu contrast over bright/moving video in every theme and orientation. Check keyboard/touch/remote focus, long labels, system text sizes and captions. - Test real protected media, rotation/background, cancellation, sign-out, repeated switching, stream release and long-running recovery on each target device/OS. - Test offline cold start/expiry/renewal only on supported phone/tablet paths. - Pin SDK versions and qualify the actual packaged application. A build, unit test or capability flag is not device certification or production acceptance.