Skip to content

Release notes

Current versions at a glance:

PlatformVersionInstall from
Android1.6.0tv.ogplayer:* on the OGPlayer Maven repository
iOS1.6.0Swift Package Manager
Web1.6.0ogplayer on npm
React Native1.6.0ogplayer-react-native on npm
Flutter1.6.1ogplayer_flutter on pub.dev
Smart TV1.6.0Android TV, Google TV and Fire TV in the Android SDK · Apple TV in the iOS SDK · Samsung Tizen and LG webOS as ogplayer/tv in the web package

Minor releases land on every platform, and a platform can lead when a feature is its own (1.3.0 brought the TV chrome to Android and iOS first); patch versions move independently per platform — a platform-specific fix ships only where it applies. Notes below are grouped per platform, newest first. All platforms share the same 1.0.0 foundation, described once at the bottom of this page.

Every word the player chrome shows or speaks can now be supplied by the host: one strings map, English by default, applied to the controls, the menus, the live chip, the ad bar, the error overlay, the vertical feed and the download notification.

  • OGStrings — a data class with every chrome string (English defaults) and OGStrings.fromMap(Map<String, String>) for a partial override (missing keys stay English, unknown keys are ignored). Placeholders are {name} tokens ({seconds}, {title}, {n}, {code}, {count}, {device}, {speed}, {height}, {index}, {name}, {channels}); OGStrings.format(template, …) applies them.
  • OGUiConfig.Builder.setStrings(OGStrings) — the player chrome, including every TalkBack label.
  • OGVerticalFeedConfig.Builder.setStrings(OGStrings) — the feed’s play label, “Sponsored”, the error copy and Retry.
  • OGDownloadsConfig.Builder.setStrings(OGDownloadStrings) — the download notification’s texts.
  • The existing per-feature options keep precedence: errorMessageProvider over the generic error text, retryButtonLabel over the Retry label, upNextText over the up-next card.
  • Low-latency HLS (partial segments) is supported: the player follows the playlist’s PART-HOLD-BACK as its latency target, and the live chip, the DVR window, the behind-live state and going to the live edge work on parts.
  • Every control carries a content description; the scrub bar and the volume control are adjustable sliders with a spoken position; the LIVE chip announces “Go to live”; the volume button offers a Mute / Unmute action; the up-next card announces the next title.
  • Playback speeds read 1.5×; an audio track that shares its name with another reads Name · 6ch; the audio button’s spoken label is “Audio”.
  • Android artifacts are served from the OGPlayer Maven repository: add maven("https://maven.ogplayer.tv") { content { includeGroup("tv.ogplayer") } } to the repositories in settings.gradle.kts, after google() and mavenCentral().

Drop-in for 1.5.0 once the repository line is in place: all additions are additive.

Maintenance release.

Drop-in for 1.4.1: no API changes.

Live streams and the speed option; cast metadata in minified apps.

  • The speed option is not offered on live streams; the setting keeps its effect on on-demand content.
  • Casting from an R8-minified app: the media item’s stream type reaches the receiver — the keep rule ships with the SDK, no host-app ProGuard rule needed.

Source and binary compatible with 1.4.0: no API changes.

Bug fixes and improvements: hardening across playback, ads, cast, downloads and the chrome, on phones and Android TV.

  • OGMediaItem.Builder.setMimeType(String) declares a manifest’s type when the URL does not (application/x-mpegURL, application/dash+xml) — on the device and on a cast receiver.
  • CastConnector.isSessionAvailable: a player built while a cast session is already running hands playback to the receiver from its first load. OGCastConnector implements it. See casting.
  • AdsProvider.setAdVolume(Float, Boolean) carries the viewer’s volume and mute to the ad. Default implementation, so existing providers compile unchanged.

Source and binary compatible with 1.3.1: every addition above is additive, and the new SPI member has a default implementation.

  • A tap on a playing ad pauses it and brings up the play glyph; the glyph resumes the ad and leaves with it. Google IMA’s own skip button and clickthrough keep working. A custom ads provider reports a tap through AdsProviderCallbacks.onAdTapped(AdInfo) and the SDK toggles the ad for it.
  • Learn more (the ad’s clickthrough) pauses the ad while the browser covers the app and resumes it when the viewer comes back. AdListener.onAdClicked(AdInfo) reports the click; a custom ads provider raises it through AdsProviderCallbacks.onAdClicked(AdInfo). See ads.
  • Android TV: the playlist previous/next glyphs are replaceable like the rest of the chrome — OGUiConfig.Builder.setSkipPreviousIcon(res) / setSkipNextIcon(res), drawn as delivered at the TV glyph size. See theming.
  • Nothing is drawn over a playing ad. The play glyph appears only while the ad is paused — after a tap, a media key, the lock screen or pause() — with a soft shadow instead of a rim; host ad icons (setAdPlayIcon / setAdPauseIcon) get the same treatment.
  • Automation ids: og_btn_ad_play_pause exists only while an ad is paused; og_ad_chrome marks the ad bar for the whole break.

Binary and source compatible with 1.3.0: the new AdsProviderCallbacks and AdListener members have default implementations; OGUiConfig gained two builder setters.

  • Android TV, Google TV and Fire TV. The same tv.ogplayer artifacts now carry a remote-control chrome. OGUiConfig.Builder.setInputMode(OGInputMode.REMOTE) switches the built-in controls to D-pad driving: focus is shown by size (no rings), OK activates, Left/Right seek from the scrub bar with the storyboard preview and accelerating steps, the remote’s media keys act directly, and sizes and insets step up for viewing distance with an overscan-safe layout. Touch keeps working alongside. The switch is explicit — the SDK never infers a television; isTelevision(context) is the one-line check for an app that ships one APK to phones and TVs. See the Android TV quick start.
  • OGUiConfig.Builder.setMediaSessionEnabled(true) (remote mode): a framework MediaSession mirrors the player, so voice commands, the system’s now-playing row and media buttons from other surfaces reach it.
  • Ads on the remote chrome: an ad break is driven from the same bar (play/pause, ad progress on the scrub line). Right or Up from the ad transport steps into the ad’s own UI — skip, “About this ad” — and Back steps out. AdsProvider.focusUi() and AdsProviderCallbacks.onAdUiDialogChanged(Boolean) expose that hand-off to custom ad providers.
  • A television glyph set, drawn on a pixel grid for 1080p panels. Phones keep their icons.
  • Playlists on the remote chrome: previous and next buttons flank play/pause, each shown while there is an item that way; the remote’s previous/next media keys do the same. OGPlayer.skipToPrevious() joins skipToNext() for hosts with their own controls.
  • Remote mode hides an option button with nothing to choose — one audio track, no text tracks, a single quality — instead of dimming it, so the D-pad never lands on a dead control.
  • Remote mode does not offer the fullscreen, cast and volume buttons: a TV app is always full-screen, has no cast sender, and the remote owns the volume. Their setShow* flags are accepted and ignored there.
  • Remote mode: an open menu closes together with the chrome after seven seconds without a press; browsing the rows restarts the clock.
  • Pointer mode (phones and tablets) is unchanged: the chrome renders exactly as in 1.2.2.

Binary compatible with 1.2.x for ogplayer-core, ogplayer-ads-ima, ogplayer-cast and ogplayer-ads-freewheel; the new AdsProvider members have defaults. ogplayer-ui is source compatible: the focusRing colour and focusRingWidth dimension were removed from OGControlColors and OGControlDimens (focus is shown by size), which changes the data-class constructors — apps using named arguments or the builders are unaffected. ogplayer-ui now depends on androidx.activity:activity-compose.

  • OGPlayerSdk.VERSION reported 1.2.0 in 1.2.1. It now reports the released version.

Binary and source compatible with 1.2.1. No other changes.

  • Playback engine updated to Media3 1.11.1: fixes for a stall when a secondary renderer is pre-warmed for a transition, a crash when a live timeline refresh moves the default position past a server-side ad in progress, audio-offload stalls during pre-roll and gapless transitions, an HLS chunk that retried after end-of-stream, and a NullPointerException when a MediaController is released from inside a player listener.
  • Chrome: an option button (speed, quality, audio, subtitles) is drawn white whenever it is shown. Only a button with nothing to offer — one audio track, no text tracks, a single quality — is dimmed. The current selection is shown in the button’s menu, not in the icon.

Binary and source compatible with 1.2.0. No API changes.

  • AnalyticsEvent.PlaybackRecovered(reason, positionMs): the SDK reports the recoveries it performs on its own, so your analytics can count them. The RecoveryReason says why — DRM_RENEWAL_AFTERSHOCK (a re-prepare right after a license renewal), CODEC_RESTART (a decoder rebuilt in place) or LIVE_WINDOW_RESET (a live stream re-joined at the edge). Playback continues at the reported position in every case.
  • ActivityFullscreenHandler.release(): call it when the player that owns the handler goes away. A deferred orientation restore is applied right then, so the next screen starts with its own orientation settings.
  • Long DRM sessions: a license that expires mid-stream is renewed inside the SDK and playback resumes at the same position. The app sees at most a PlaybackRecovered event, never an error.
  • Encrypted audio on Android 15+ no longer registers with the platform’s automatic loudness configuration (CTA-2075); clear content and video are unchanged.
  • DRM content: a decoder that fails to start is retried once with a fresh license before the failure is reported.
  • HLS streams whose media does not match the playlist’s track layout report 3000 SOURCE_MALFORMED instead of a network error.

Binary compatible with 1.1.0. Source note: an exhaustive when over AnalyticsEvent needs a branch for PlaybackRecovered.

  • Offline downloads with offline DRM: download VOD — persistent Widevine license included, acquired through your existing token flow — and play it fully offline, zero network. Foreground download service ships in the SDK; new stable error codes 7100–7102 and 4006.
  • Picture-in-picture: pass an ActivityPipHandler to enable — auto-enter on leaving the app, imperative enterPip(), a play/pause action on the window, and dismiss-pauses semantics. No chrome button: whether your app offers PiP is your call.
  • Analytics: every event now carries a per-load sessionId and assetUrl; seven new events (PlaybackStarted with startup time, VolumeChanged, TextTrackChanged, AudioTrackChanged, FullscreenChanged, PictureInPictureChanged, OrientationChanged); BufferStart now says why (INITIAL/SEEK/REBUFFER) and QualitySnapshot adds live latency and at-live-edge fields.
  • Breaking (analytics only): the parameterless AnalyticsEvent singletons are now classes — BufferStart carries reason, and Play, Pause, BufferEnd, DrmKeysLoaded and Complete became classes for session stamping. Code that used them as values (AnalyticsEvent.Play) now constructs them (AnalyticsEvent.Play()); is-checks and when matching are unaffected.
  • Recompile against 1.1.0 rather than mixing with 1.0.x-compiled code — new optional parameters changed method signatures under the hood.
  • Stability fixes across fullscreen/orientation handling, casting and ads session edge cases.
  • Automation IDs inside menu popups (og_menu, og_menu_item, og_volume_slider) are now exposed as resource-ids — popup windows don’t inherit the player root’s automation configuration.
  • Automation IDs: one canonical og_* identifier set exposed as resource-ids on every interactive element of the player and the vertical feed.
  • Overlay slots no longer collide with the player controls: when the chrome is visible the whole overlay grid shrinks between the control bars as one unit, so top-row overlays can’t land on centre-row anchors.
  • Vertical feed: in both split layouts (text + video and split video) the host rail now anchors to the whole page.

Version-alignment release, no functional changes.

First general-availability release — see the Foundation release section at the bottom of this page.

Every word the player chrome shows or speaks can now be supplied by the host: one strings value, English by default, applied to the controls, the menus, the live chip, the ad chrome, the error overlay, the AirPlay and picture-in-picture status texts and the vertical feed — on iPhone, iPad and Apple TV alike.

  • OGStrings — a struct with every chrome string (English defaults), OGStrings(map: [String: String]) for a partial override (missing keys stay English, unknown keys are ignored) and OGStrings.english. Placeholders are {name} tokens ({seconds}, {title}, {n}, {code}, {device}, {speed}, {height}, {index}, {count}, {name}, {channels}); OGStrings.format(_:_:) applies them.
  • OGUIConfig.strings — the player chrome, including every VoiceOver label.
  • OGVerticalFeedConfig.strings — the feed’s play label, “Sponsored”, the error copy and Retry.
  • The existing options keep precedence: errorMessageProvider over the generic error text, retryButtonLabel over the Retry label, upNextText over the up-next card.
  • OGControlColors.adAccent — the ad-bar accent token under its documented name; accent remains as an alias of the same value, and an adAccent: initialiser sits next to the existing one.
  • Low-latency HLS (partial segments) is supported: the player follows the playlist’s PART-HOLD-BACK as its latency target, and the live chip, the DVR window, the behind-live state and going to the live edge work on parts.
  • VoiceOver labels on every control: play, pause and replay, the seek buttons with their step, volume, speed, quality, audio, subtitles, fullscreen, and previous / next on the Apple TV remote chrome; the scrub bar and the volume slider report their position; the LIVE chip announces “Go to live”; the volume button offers a Mute / Unmute action; the up-next card announces the next title.
  • BitrateChanged reports the rendition that reached the screen — the initial selection and each completed variant switch — with the variant’s declared resolution and frame rate; a loader’s trial fetch of a neighbouring variant no longer counts, and switches carry the new variant’s size instead of the previous one.
  • The chrome’s texts come from OGUIConfig.strings only; they no longer resolve through the host app’s Localizable.strings.
  • Playback speeds read 1.5×; an audio track that shares its name with another reads Name · 6ch.

Drop-in for 1.5.0: all additions are additive.

Maintenance release.

Drop-in for 1.4.1: no API changes.

Live streams and the speed option.

  • The speed option is not offered on live streams; the setting keeps its effect on on-demand content.

Source and binary compatible with 1.4.0: no API changes.

Bug fixes and improvements: hardening across playback, ads, downloads, Picture in Picture and the chrome, on iPhone, iPad and Apple TV.

  • OGMediaItem.mimeType declares a manifest’s type when the URL does not (application/x-mpegURL, application/dash+xml).
  • AdsProvider.setVolume(_:muted:), .setAutostart(_:) and .setResumePosition(_:): the ads SPI gains the viewer’s volume, whether a loaded break may start on its own, and the position a resumed item starts from. Default implementations, so existing providers compile unchanged.

Source compatible with 1.3.1: every addition above is additive, and the new SPI members have default implementations.

  • A tap on a playing ad pauses it and brings up the play glyph; the glyph resumes the ad and leaves with it. Google IMA’s own skip button and clickthrough keep working. A custom ads provider reports a tap through AdsProviderCallbacks.onAdTapped(_:) and the SDK toggles the ad for it.
  • Learn more (the ad’s clickthrough) pauses the ad while the browser covers the app and resumes it when the viewer comes back. AdListener.onAdClicked(_:) reports the click; a custom ads provider raises it through AdsProviderCallbacks.onAdClicked(_:). See ads.
  • Apple TV: the playlist previous/next glyphs are replaceable like the rest of the chrome — OGUIConfig.skipPreviousIcon / skipNextIcon, drawn through the same path as every other custom glyph. See theming.
  • Nothing is drawn over a playing ad. The play glyph appears only while the ad is paused — after a tap, the lock screen, Control Center or pause() — with a soft shadow instead of a rim; host ad icons (adPlayIcon / adPauseIcon) get the same treatment.
  • Automation ids: og_btn_ad_play_pause exists only while an ad is paused; og_ad_chrome marks the ad bar for the whole break.

Source compatible with 1.3.0: the new AdsProviderCallbacks and AdListener members have default implementations, so existing providers and listeners compile unchanged. OGUIConfig gained two optional images.

  • Apple TV. The Swift package builds for tvOS 18: OGPlayerCore and OGPlayerUI are the same products, and OGPlayerAdsIMAtvOS brings Google IMA ads through the tvOS IMA SDK. On tvOS the built-in chrome is driven by the Siri Remote: play/pause centred in the bottom row with the options beside it, focus shown by size, Left/Right seek from the scrub bar with the storyboard preview and accelerating steps, media keys act directly, and an overscan-safe layout sized for viewing distance. See the Apple TV quick start.
  • OGUIConfig.mediaSessionEnabled on tvOS: a Now Playing session mirrors the player, so Siri, Control Center and the remote’s media buttons reach it.
  • Playlists on the remote chrome: previous and next buttons flank play/pause, each shown while there is an item that way; the Now Playing previous/next commands do the same. OGPlayer.skipToPrevious() joins skipToNext().
  • On tvOS an option button with nothing to choose is hidden rather than dimmed, so the remote never lands on a dead control; fullscreen, AirPlay and volume are not offered there.
  • An open menu closes together with the chrome after seven seconds without a press; browsing the rows restarts the clock.
  • Sideloaded-subtitle cues: the background now hugs the text, as Android’s caption renderer draws it, instead of spanning the cue box. iPhone and iPad see no other visual change.

Binary and source compatible with 1.2.x on iOS. New tvOS product OGPlayerAdsIMAtvOS depends on Google’s tvOS IMA package.

  • OGPlayerSDK.version reported 1.2.0 in 1.2.1. It now reports the released version.

Binary and source compatible with 1.2.1. No other changes.

  • Chrome: an option button (speed, quality, audio, subtitles) is drawn white whenever it is shown. Only a button with nothing to offer — one audio track, no text tracks, a single quality — is dimmed. The current selection is shown in the button’s menu, not in the icon.

Binary and source compatible with 1.2.0. No API changes.

  • FairPlayConfig.renewalInterval: for license servers that lease FairPlay keys for a fixed time, set the interval (a little under the lease) and the SDK renews the key in the background before it expires — through your token provider like any other license request, with onDrmSessionRenewed(.proactive) on each renewal. nil, the default, keeps the current behaviour. Both FairPlayConfig initialisers take the new optional parameter.
  • Error reporting is more specific: HTTP failures on the manifest, segments and key requests surface with the status-specific code (2404 for a missing manifest, for example) and DRM license failures carry the license server’s reason in the message. A 9000 UNKNOWN error now includes a summary of the underlying error chain, so support tickets come with the cause attached.
  • FairPlay key-exchange failures report their real code — an HTTP status from the license or certificate request, a token provider failure — rather than a generic DRM error.

Additive — no breaking API changes; safe upgrade from 1.1.2.

  • Vertical feed: the rail’s accessibility identifiers were unreachable. SwiftUI propagates a container’s accessibilityIdentifier to every descendant, so the page identifier (og_feed_page_<n>) was stamped onto everything inside the page — og_feed_rail, og_feed_rail_action_<n>, og_feed_sponsored_badge and og_feed_hairline did not exist as far as an accessibility client was concerned, and every rail button reported the page’s identifier instead of its own. The page and the rail are now proper accessibility containers, so each element keeps its own identifier. This matters if you drive the feed from UI tests or inspect it with assistive technology; nothing about the rendered feed changes.

Additive — no API changes; safe upgrade from 1.1.1.

  • Picture-in-picture: with pipEnabled and autoEnterPipOnBackground: false, leaving the app could still open a PiP window on recent iOS versions — the system auto-enters PiP for any PiP-capable player, ignoring the opt-out flag. The SDK now keeps no PiP controller while auto-enter is disabled, so leaving the app pauses playback as configured; an explicit enterPip() still works.

Additive — no API changes; safe upgrade from 1.1.0.

  • Offline downloads with offline DRM: download VOD — FairPlay keys persisted alongside, acquired through your existing token flow — and play it fully offline. OGDownloadManager.shared is an ObservableObject with @Published downloads, ready to drive SwiftUI lists; new stable error codes 7100–7102 and 4006.
  • Picture-in-picture: pipEnabled plus a two-way isPipActive binding — auto-enter on backgrounding, and an onPipRestoreUserInterface hook for the “back to app” transition. No chrome button: whether your app offers PiP is your call.
  • Analytics: every event now delivered with a per-load sessionId and assetUrl (the listener protocol gained onEvent(_:sessionId:assetUrl:) with a default implementation — existing listeners keep compiling); seven new events (playbackStarted with startup time, volumeChanged, textTrackChanged, audioTrackChanged, fullscreenChanged, pictureInPictureChanged, orientationChanged); bufferStart now says why and qualitySnapshot adds live latency and at-live-edge fields.
  • Breaking (analytics): bufferStart now carries a reason associated value and qualitySnapshot gains two (live latency, at-live-edge) — update case let patterns accordingly; exhaustive switches over AnalyticsEvent need cases (or a default) for the seven new events.
  • Breaking (DRM): FairPlayConfig.tokenProvider is now async throws. A failing/throwing provider surfaces as error 4002 (and a failed FairPlay certificate fetch as 4003) instead of silent license failure.
  • Stability fixes across fullscreen/rotation handling, ads and AirPlay session edge cases.
  • Scrubbing to the very end of a video could leave a stuck buffering spinner — end seeks now land just short of the duration so playback finishes naturally into the ended state.
  • Seeking after playback ended now resumes playing at the new position (previously only replay-from-start was possible).
  • The og_player, og_menu and og_error_overlay container identifiers no longer override their children’s accessibility identifiers, so every documented element ID is reachable from UI tests.
  • Automation IDs: one canonical og_* identifier set exposed as accessibility identifiers on every interactive element of the player and the vertical feed.
  • Overlay slots no longer collide with the player controls: when the chrome is visible the whole overlay grid shrinks between the control bars as one unit, so top-row overlays can’t land on centre-row anchors.
  • Vertical feed: in both split layouts (text + video and split video) the host rail now anchors to the whole page.
  • The vertical feed’s paused-state glyph now uses the SDK’s own icon set (was a system symbol, optically off-center).

First general-availability release — see the Foundation release section at the bottom of this page.

The player now plays MPEG-DASH next to HLS — VOD and live, Widevine and PlayReady, on desktop browsers and on the smart-TV bundle — and every word of its chrome can be supplied by the host.

  • An .mpd URL, or mimeType: "application/dash+xml" on an extensionless one, plays through a DASH engine (dash.js 5.2) on every MSE browser; Safari keeps its native HLS path. Same API, events, menus, thumbnails and analytics as HLS; quality, audio and subtitle menus come from the manifest; live and DVR windows work as on HLS.
  • Playback starts on the manifest’s own audio choice — the highest @selectionPriority, then Role main, then the first AdaptationSet listed — the DASH counterpart of an HLS DEFAULT=YES rendition. Every load starts there, as on HLS; no earlier track pick carries over.
  • DRM through the same DrmConfig: widevine and playready with the same tokenProvider, renewal analytics and error codes.
  • The engine loads only when a DASH item plays, and nothing changes for HLS-only pages: the ESM build fetches a chunk (dist/ogplayer.dash-*.js) on demand; <script> pages and packaged TV apps add dist/ogplayer.dash.global.js next to the bundle. A host that bundles its own dash.js passes it as new OGPlayer({ dashjs }). A DASH item on a page without the engine file reports error 3001 with the file name in the message.
  • The TV bundle (ogplayer/tv) plays DASH on Samsung Tizen and LG webOS the same way, with the TV buffer profile and the remote chrome’s quality pick applied.
  • OGPlayer.enterPip() / exitPip() / isInPip — picture-in-picture from the host’s own code (the standard API, or Safari’s presentation mode where only that exists). enterPip() resolves false rather than throwing when the browser offers no PiP, nothing is loaded, or an ad break owns the screen; a break that starts while in PiP brings the player back; unload() and release() leave PiP.
  • OGPlayerOptions.autoEnterPip — opts in to the browser’s own automatic PiP where it offers one (Safari’s autoPictureInPicture, Chrome’s media-session control).
  • Analytics PictureInPictureChanged { isActive }, the og-pipchanged element event and PlaybackListener.onPipChanged report every transition. The chrome shows no PiP control; the host decides when.
  • Low-latency HLS (partial segments) is supported on the default profile: the player follows the playlist’s PART-HOLD-BACK as its latency target, and the live chip, the DVR window and going to the live edge work on parts. The TV profile keeps low-latency mode off, as before.
  • Going to the live edge — the LIVE chip, the End key, seekToLiveEdge() — now lands on the stream’s live sync point instead of the newest segment boundary, so playback resumes without a stall on every live stream.
  • OGUIConfig.strings — a partial map of every chrome string, merged over the English defaults (type OGStrings; placeholders are {name} tokens). OGUIConfig.locale and the <og-player lang> attribute set the language used for audio and subtitle track names (default en). OGVerticalFeedConfig.strings for the feed. OGPlayer.strings and OGPlayer.locale mirror the same values on the core.
  • The existing options keep precedence: errorMessageProvider over the generic error text, retryButtonLabel over the Retry label, upNextText over the up-next card.
  • Every control carries an aria-label; the scrub bar and the volume slider are sliders with a spoken position; the LIVE chip is a button that announces “Go to live”; the volume button reads Mute or Unmute; the fullscreen button reads enter or exit; the up-next card announces the next title.
  • A fatal error now ends the session: the player stops loading, pauses, and reports nothing further for that item until retry() or a new load(). A browser without the configured DRM system reports 4005 DRM_UNSUPPORTED, naming the schemes (for example Widevine on Safari), instead of a license failure.
  • On live streams the progress bar moves smoothly between playlist updates, also on short low-latency windows.
  • An unnamed multichannel audio track reads German · 6ch (was German (5.1)).
  • On an HLS live stream the DVR window — LiveInfo.dvrWindowMs, the scrub span, the behind-live state — now matches the playlist’s sliding window instead of growing from the first loaded segment.
  • On the TV profile a manual quality pick settles on every rendition size, including ones whose decoded frame is a pixel off the advertised size.

hls.js stays the package’s only npm dependency; the DASH engine ships inside the package. Drop-in for 1.5.0.

Smart TVs: the package ships a second bundle, ogplayer/tv, for Samsung Tizen (5.5 and newer) and LG webOS (5 and newer) — the same API, compiled for the browser engines those sets run, with a remote-control chrome for the living room.

  • ogplayer/tv (dist/ogplayer.tv.js, dist/ogplayer.tv.global.js) — the bundle for packaged TV apps. Chromium 68/69 floor; no vertical feed.
  • <og-player input="remote"> — the remote-control chrome: D-pad focus, OK, Back, media keys, key-driven scrubbing with storyboard preview, quality, audio and subtitle menus, previous/next around play/pause. Back with the chrome down fires og-back, so the host decides where Back goes.
  • OGPlayerOptions.platformProfile: "tv" — buffer targets and start-up quality for set-top hardware; on this profile a manual quality pick re-buffers on the chosen rung immediately and the chrome shows a pending ring until it plays. tvHlsProfile, bufferTargets and the PlatformProfile type are exported.
  • OGPlayer.skipToPrevious() — playlist previous, the twin of skipToNext().
  • OGUIConfig.skipPreviousIconSvg / skipNextIconSvg — custom glyphs for the two playlist controls.
  • Ads on a remote: OGPlayer.focusAdUi() and OGPlayer.isAdUiDialogOpen, AdsProvider.focusUi?, AdsProviderCallbacks.onAdUiDialogChanged?, ImaAdsProvider.focusUi() — the remote can step into an ad’s own controls and the chrome knows while a dialog is open.

The browser bundle is a drop-in for 1.4.1.

Maintenance release.

Drop-in for 1.4.0: no API changes.

Bug fixes and improvements: hardening across playback, ads, DRM and the chrome.

  • OGPlayer.unload() drops the media pipeline without tearing the player down — for a card scrolled out of view, a hidden tab, a route the viewer left.
  • AdsProvider.setVolume?(volume, muted) carries the viewer’s volume and mute to the ad. Optional, so existing providers are unaffected.
  • onLicenseChanged(...) returns an unsubscribe function.

Source compatible with 1.3.1: every addition above is additive, and the new provider member is optional.

  • The ad bar carries the ad’s play/pause for the whole break (og_btn_ad_play_pause, label Pause ad / Resume ad). adPlayIconSvg / adPauseIconSvg restyle it; Space and K toggle the ad the way they toggle content.
  • Learn more (the ad’s clickthrough) pauses the ad while another tab or window covers the page and resumes it when the viewer comes back. onAdClicked(ad) on the ad listener reports the click; a custom ads provider raises onAdTapped(ad) and onAdClicked(ad) on its callbacks. See ads.
  • og_ad_chrome marks the ad bar for the whole break (automation id).
  • Nothing sits over a playing ad: the centred ad transport is gone. A click on the creative is the ad’s clickthrough; the bar button is the transport.

Drop-in for 1.2.2. Additive; no existing API changes.

  • Keyboard shortcuts while the player has focus: Space/K play-pause, ←/→ and J/L seek by the seek increment, ↑/↓ volume, M mute, F fullscreen, C subtitles, 0–9 jump to 0–90 % on VOD, Home/End start/end (live edge on live), Esc leaves fullscreen. Seek keys follow the live rules and stay inert during ads; modifier chords and unmapped keys reach the page untouched. keyboardShortcuts: false hands the keyboard back to the host; keymap remaps or removes single keys.

Drop-in for 1.2.1. Additive; no existing API changes.

  • hls.js updated to 1.7.3: subtitle selection stays correct when subtitles are turned off while segments are still loading, audio selection honours assocLang, a seek into a gap at the end of a stream no longer collapses the duration, and a live playlist can no longer reload itself recursively when its last segment is shorter than the round trip.
  • Chrome: the quality, audio and subtitle buttons are disabled and dimmed when the stream offers nothing to choose — one audio track, no text tracks, a single quality. Every other shown button is drawn white; the current selection is shown in the button’s menu.

Drop-in for 1.2.0. No API changes.

  • PlaybackRecovered event: the player reports the recoveries it performs on its own — a retried segment or manifest load (NETWORK_RETRY), a stall nudged over (BUFFER_STALL), a retried key request (DRM_RETRY) or a media fault recovered in place (MEDIA_RETRY) — with the position and a short detail. Count them in analytics; playback continues in every case.
  • HTTP failures carry the status in the code: 2000 + status for manifest and segment requests, 4000 + status for license requests, with matching codeNames.
  • Behavior change in error reporting: recoveries the player handles by itself no longer arrive as Error events — they are PlaybackRecovered now. An Error means playback stopped. If you counted errors the player recovered from, count PlaybackRecovered instead.
  • Control sync tolerates host-side changes inside the player’s shadow root.

Additive — no breaking API changes; safe upgrade from 1.1.1.

  • Desktop mouse and keyboard conventions: clicking the video toggles play/pause, the spacebar toggles play/pause once the player has focus (it takes focus on any click), and moving the mouse over the player raises the auto-hidden controls. See Controls for the full show/hide model.
  • Behavior change on desktop: a mouse click on the video now pauses/resumes instead of hiding the controls — hovering handles showing them, and the idle timeout handles hiding. Touch input is unchanged: a tap still toggles the controls.

No API changes — safe upgrade from 1.1.0; review the desktop click behavior change above if your UI relied on click-to-hide.

  • Analytics: every event now carries a per-load sessionId and assetUrl; new events (PlaybackStarted measured to the first composited frame, VolumeChanged, TextTrackChanged, AudioTrackChanged, FullscreenChanged, OrientationChanged); BufferStart now says why (INITIAL/SEEK/REBUFFER) and QualitySnapshot adds live latency and at-live-edge fields.
  • Seeking after playback ended now resumes playing at the new position (previously the position moved but playback stayed stranded).
  • Assorted stability fixes.
  • The ad-blocker notice overlay copy now matches its behavior: content keeps playing ad-free and the overlay politely suggests allowing ads, with a “Got it” dismissal (it previously told viewers to allow ads and reload, which contradicted the keep-playing policy).
  • npm package metadata: the package page now links to the getting-started guide and a public issue tracker.

Additive — no breaking changes; safe upgrade from any 1.0.x.

Version-alignment release, no functional changes.

  • Automation IDs: one canonical og_* identifier set exposed as data-testid on every interactive element of the player and the vertical feed.
  • Overlay slots no longer collide with the player controls: when the chrome is visible the whole overlay grid shrinks between the control bars as one unit, so top-row overlays can’t land on centre-row anchors.
  • Scrub-preview thumbnails cut from wide sprite sheets rendered as a black box; frames now scale and clamp correctly.
  • Vertical feed: in both split layouts (text + video and split video) the host rail now anchors to the whole page.
  • On split-video feed pages the host rail anchors to the whole page — both halves are video — instead of the top half.

First general-availability release — see the Foundation release section at the bottom of this page.

Wraps OGPlayer Android 1.6.0 and OGPlayer iOS 1.6.0.

  • Supports Flutter 3.29 / Dart 3.7 and newer, as documented.
  • Android hosts build on Android Gradle Plugin 8 or 9; on AGP 8 the plugin applies the Kotlin Android plugin itself. Android apps compile against compileSdk 36 with Kotlin 2.1+, as the playback engine requires.

Drop-in for 1.6.0: no API changes.

Wraps OGPlayer Android 1.6.0 and OGPlayer iOS 1.6.0. Every word the player chrome shows or speaks can now be supplied from Dart: one OGStrings value, English by default, applied to the controls, the menus, the live chip, the ad bar, the error overlay and the vertical feed on both platforms.

  • OGStrings — a const class with every chrome string as an optional field (unset keys stay English) and OGStrings.fromMap(Map<String, String>) for a flat map shared with other platforms (unknown keys are ignored). Placeholders are {name} tokens ({seconds}, {title}, {n}, {code}, {device}, {speed}, {height}, {index}, {count}, {name}, {channels}).
  • OGUIConfig.strings — the player chrome, including every spoken label.
  • OGVerticalFeedConfig.strings — the feed’s play label, “Sponsored”, the error copy and Retry.
  • OGUIConfig.locale — accepted for parity with the web SDK; the native players name tracks their own way.
  • The existing options keep precedence: errorMessages over the generic error text, retryButtonLabel over the Retry label, upNextText over the up-next card.
  • OGPlayerViewController.getLiveInfo() → Future<LiveInfo?> — the live stream’s DVR window, live-edge state, distance behind the edge and the playhead’s wall-clock time (playheadWallClockMs), so an app can show how far behind real time the viewer is watching; null for VOD.
  • OGUIConfig.colors (OGControlColors) and OGUIConfig.dimens (OGControlDimens) — the native chrome’s colour and size tokens under the same names as in the native SDKs: 16 colours (#RRGGBB or #AARRGGBB) and 23 sizes (dp / pt), each documented with its default; unset tokens keep the SDK default. Ten of the sizes shape the embedded chrome; the players keep their own values in fullscreen. An invalid value is skipped, never fatal.
  • Every control now carries a spoken label on both platforms (TalkBack and VoiceOver): play, pause and replay, the seek buttons with their step, volume, speed, quality, audio, subtitles and fullscreen; the scrub bar and the volume slider report their position; the LIVE chip announces “Go to live”; the volume button offers Mute / Unmute; the up-next card announces the next title.
  • Playback speeds read 1.5×; an audio track that shares its name with another reads Name · 6ch.

Drop-in for 1.5.0: all additions are additive.

Wraps OGPlayer Android 1.5.0 and OGPlayer iOS 1.5.0. Maintenance release.

Drop-in for 1.4.1: no API changes.

Wraps OGPlayer Android 1.4.1 and OGPlayer iOS 1.4.1. Bug fixes.

Drop-in for 1.4.0: no API changes.

Wraps OGPlayer Android 1.4.0 and OGPlayer iOS 1.4.0. Bug fixes and improvements.

Drop-in for 1.3.1: no API changes.

Wraps OGPlayer Android 1.3.1 and OGPlayer iOS 1.3.1.

  • A tap on a playing ad pauses it and brings up the play glyph; the glyph resumes the ad and leaves with it. Learn more (the ad’s clickthrough) pauses the ad while the browser covers the app and resumes it when the viewer comes back. onAdEvent reports the click as type clicked.
  • OGPlayerController.skipToPrevious() goes back one playlist item, the counterpart of skipToNext().
  • Nothing is drawn over a playing ad: the play glyph appears only while the ad is paused.

Drop-in for 1.2.3. Additive; no existing API changes.

Wraps OGPlayer Android 1.2.2 and OGPlayer iOS 1.2.2.

  • iOS: the player now keeps a single view controller for its lifetime. Leaving fullscreen, or changing uiConfig, while a Google IMA ad is on screen keeps IMA’s ad UI attached for the rest of the ad session and no longer terminates the app.

Drop-in for 1.2.2. No API changes.

Wraps OGPlayer Android 1.2.2 and OGPlayer iOS 1.2.2.

  • Android engine updated to Media3 1.11.1 (renderer pre-warming, live timelines with server-side ads, audio offload, HLS end-of-stream retries).
  • Player chrome on both platforms: an option button (speed, quality, audio, subtitles) is drawn white whenever it is shown; only a button with nothing to offer — one audio track, no text tracks, a single quality — is dimmed. The current selection is shown in the button’s menu.

Drop-in for 1.2.0. No API changes.

Wraps OGPlayer Android 1.2.0 and OGPlayer iOS 1.2.0.

  • PlaybackRecoveredEvent (reason, positionMs): the player reports the recoveries it performs on its own, so your analytics can count them; RecoveryReason says why. Android; on iOS these show as a BufferStart/BufferEnd pair.
  • FairPlayConfig.renewalInterval: for license servers that lease FairPlay keys for a fixed time, set it a little under the lease and the key is renewed in the background through your token provider.
  • Long DRM sessions on Android: a license that expires mid-stream is renewed and playback resumes at the same position — at most a PlaybackRecoveredEvent, never an error.
  • Leaving a player screen no longer changes the orientation of the screen that follows it.

Additive — safe upgrade from 1.1.1.

  • Example app: a real README (the 1.1.0 package shipped the Flutter template text).

No code changes — safe upgrade from 1.1.0.

Initial release — wraps OGPlayer Android 1.1.0 and OGPlayer iOS 1.1.2.

  • OGPlayerView widget + OGPlayerViewController: VOD/live/live-DVR, multi-DRM with a Dart tokenProvider, Google IMA ads, playlists with the “Up next” card, picture-in-picture, subtitles/audio/quality selection, fullscreen (button + rotate), watermark overlays, full chrome configuration down to headless.
  • OGVerticalFeedView widget: the swipeable portrait video feed — pooled preloaded neighbours, split text/video layouts, sponsored items, host-owned rail actions.
  • OGDownloads: offline downloads with offline DRM, license renewal, and a broadcast event stream.
  • One mirrored API and event union across the OGPlayer SDKs.

iOS hosts forward supportedInterfaceOrientationsFor and handleEventsForBackgroundURLSession to the plugin — see the package README.

Wraps OGPlayer Android 1.6.0 and OGPlayer iOS 1.6.0. Every word the player chrome shows or speaks can now be supplied from JavaScript: one strings object, English by default, applied to the controls, the menus, the live chip, the ad bar, the error overlay and the vertical feed on both platforms.

  • OGUIConfig.strings?: Partial<OGStrings> — a partial map of every chrome string (the OGStrings type lists all keys with their English defaults). Missing keys stay English; placeholders are {name} tokens ({seconds}, {title}, {n}, {code}, {device}, {speed}, {height}, {index}, {count}, {name}, {channels}).
  • OGVerticalFeedConfig.strings?: Partial<OGStrings> — the feed’s play label, “Sponsored”, the error copy and Retry.
  • OGUIConfig.locale?: string — accepted for parity with the web SDK; the native players name tracks their own way.
  • The existing options keep precedence: errorMessages over the generic error text, retryButtonLabel over the Retry label, upNextText over the up-next card.
  • ref.getLiveInfo(): Promise<LiveInfo | null> — the live stream’s DVR window, live-edge state, distance behind the edge and the playhead’s wall-clock time (playheadWallClockMs), so an app can show how far behind real time the viewer is watching; null for VOD.
  • OGUIConfig.colors?: Partial<OGControlColors> and OGUIConfig.dimens?: Partial<OGControlDimens> — the native chrome’s colour and size tokens, with the same names as in the native SDKs: 16 colours (#RRGGBB or #AARRGGBB, like the wrapper’s other colour props) and 23 sizes (dp / pt), each documented with its default. Ten of the sizes shape the embedded chrome; the players keep their own values in fullscreen. An invalid value is skipped, never fatal.
  • Every control now carries a spoken label on both platforms (TalkBack and VoiceOver): play, pause and replay, the seek buttons with their step, volume, speed, quality, audio, subtitles and fullscreen; the scrub bar and the volume slider report their position; the LIVE chip announces “Go to live”; the volume button offers Mute / Unmute; the up-next card announces the next title.
  • Playback speeds read 1.5×; an audio track that shares its name with another reads Name · 6ch.

Drop-in for 1.5.0: all additions are additive.

Wraps OGPlayer Android 1.5.0 and OGPlayer iOS 1.5.0. Maintenance release.

Drop-in for 1.4.1: no API changes.

Wraps OGPlayer Android 1.4.1 and OGPlayer iOS 1.4.1. Bug fixes.

Drop-in for 1.4.0: no API changes.

Wraps OGPlayer Android 1.4.0 and OGPlayer iOS 1.4.0. Bug fixes and improvements.

Drop-in for 1.3.1: no API changes.

Wraps OGPlayer Android 1.3.1 and OGPlayer iOS 1.3.1.

  • A tap on a playing ad pauses it and brings up the play glyph; the glyph resumes the ad and leaves with it. Learn more (the ad’s clickthrough) pauses the ad while the browser covers the app and resumes it when the viewer comes back. onAdEvent reports the click as type: 'clicked'.
  • skipToPrevious() on the player ref goes back one playlist item, the counterpart of skipToNext().
  • Nothing is drawn over a playing ad: the play glyph appears only while the ad is paused.

Drop-in for 1.2.3. Additive; no existing API changes.

Wraps OGPlayer Android 1.2.2 and OGPlayer iOS 1.2.2.

  • iOS: the player now keeps a single view controller for its lifetime. Leaving fullscreen, or changing uiConfig, while a Google IMA ad is on screen keeps IMA’s ad UI attached for the rest of the ad session and no longer terminates the app.

Drop-in for 1.2.2. No API changes.

Wraps OGPlayer Android 1.2.2 and OGPlayer iOS 1.2.2.

  • Android engine updated to Media3 1.11.1 (renderer pre-warming, live timelines with server-side ads, audio offload, HLS end-of-stream retries).
  • Player chrome on both platforms: an option button (speed, quality, audio, subtitles) is drawn white whenever it is shown; only a button with nothing to offer — one audio track, no text tracks, a single quality — is dimmed. The current selection is shown in the button’s menu.

Drop-in for 1.2.0. No API changes.

Wraps OGPlayer Android 1.2.0 and OGPlayer iOS 1.2.0.

  • PlaybackRecovered analytics event (reason, positionMs): the player reports the recoveries it performs on its own, so your analytics can count them; RecoveryReason says why. Android; on iOS these show as a BufferStart/BufferEnd pair.
  • fairplay.renewalInterval (seconds): for license servers that lease FairPlay keys for a fixed time, set it a little under the lease and the key is renewed in the background through your tokenProvider.
  • Long DRM sessions on Android: a license that expires mid-stream is renewed and playback resumes at the same position — at most a PlaybackRecovered event, never an error.
  • Leaving a player screen no longer changes the orientation of the screen that follows it.

Additive — safe upgrade from 1.1.4.

  • iOS: updated the bundled OGPlayer iOS SDK to 1.1.2, which restores the vertical feed rail’s accessibility identifiers (see the iOS 1.1.2 notes).

Safe upgrade from 1.1.3. Wraps OGPlayer Android 1.1.0 and OGPlayer iOS 1.1.2.

  • Android: the vertical feed now applies licenseKey — licensed apps no longer show the evaluation watermark in the feed (iOS was unaffected).
  • iOS: {code} in custom errorMessages values is now substituted with the actual error code (it was Android-only).
  • iOS: clearing a custom subtitleStyle font now actually returns to the system font — previously the last custom family stuck.

Safe upgrade from 1.1.2. Wraps OGPlayer Android 1.1.0 and OGPlayer iOS 1.1.1.

  • iOS: autoEnterPipOnBackground={false} is honored — leaving the app pauses playback instead of opening a PiP window.
  • iOS: a recycled player view no longer carries pipEnabled (or any other prop) into a screen that leaves it at its default, so unrelated screens can’t inherit PiP behavior.
  • iOS: pauseOnBackground now works (it was Android-only) — backgrounding pauses and returning resumes, with PiP sessions excepted. Needed because UIBackgroundModes: audio, the PiP host requirement, disables the system’s automatic pause.
  • Android: the picture-in-picture window now shows only the video — previously it showed the whole screen scaled down.

Safe upgrade from 1.1.1. Wraps OGPlayer Android 1.1.0 and OGPlayer iOS 1.1.1.

  • iOS: the OGPlayer XCFrameworks now ship inside the npm package, so a clean npm install + pod install builds out of the box (they were previously fetched by a CocoaPods hook that never runs for the path pods React Native autolinking creates). No API changes.

Safe upgrade from 1.1.0. Wraps OGPlayer Android 1.1.0 and OGPlayer iOS 1.1.0.

  • Offline downloads with offline DRM: the new OGDownloads module — add / list / pause / resume / remove / renewLicense plus one event subscription — with transparent offline playback pickup in <OGPlayerView>; new stable error codes 7100–7102 and 4006.
  • Picture-in-picture: pipEnabled and autoEnterPipOnBackground props, enterPip() / exitPip() ref commands and the onPipChanged event. No chrome button: whether your app offers PiP is your call.
  • Analytics: onAnalyticsEvent now delivers fully structured, typed payloads (a discriminated union over every event, stamped with sessionId and assetUrl) instead of just a description string — the description field remains, so 1.0.x handlers keep working.
  • Assorted stability fixes in the native wrappers.

Wraps OGPlayer Android 1.1.0 and OGPlayer iOS 1.1.0.

  • Breaking: the error object’s recoverable field is renamed retryable, matching the name the SDK uses everywhere else. If your onError handler reads error.recoverable, change it to error.retryable — everything else is untouched. Renamed one week after launch precisely so this never has to break anyone later.

Wraps OGPlayer Android 1.0.3 and OGPlayer iOS 1.0.4.

  • npm package metadata only: the package page now links to the documentation and a public issue tracker, ships proper search keywords, and declares the real peer requirements (react-native >= 0.80, react >= 19) — a mismatched project now gets a clear peer-dependency warning at install time instead of opaque build errors.

No functional changes — safe same-day upgrade from 1.0.1. Wraps OGPlayer Android 1.0.3 and OGPlayer iOS 1.0.4.

  • First release of ogplayer-react-native: the <OGPlayerView> and <OGVerticalFeedView> Fabric components — a typed wrapper over the native Android and iOS SDKs. VOD, live & DVR, DRM with a JavaScript token provider, Google IMA ads, playlists with the Up next card, the vertical feed, watermark overlays, custom action icons, casting, full uiConfig theming and one event stream mirroring the native listeners.

Wraps OGPlayer Android 1.0.3 and OGPlayer iOS 1.0.4.

TV releases ship inside the platform SDKs, on the same version numbers — there is no separate TV package to track:

  • Android TV, Google TV and Fire TV — the Android artifacts; the remote-control chrome arrived in Android 1.3.0 and every Android release since applies.
  • Apple TV — the iOS package’s tvOS product; the Siri Remote chrome arrived in iOS 1.3.0 and every iOS release since applies.
  • Samsung Tizen and LG webOS — the ogplayer/tv bundle of the web package, from Web 1.5.0; every web release since applies.

The first general-availability release of OGPlayer: one mirrored API, production-hardened and API-stable. From here on, breaking changes only come with a major version.

Playback — VOD, live and live-DVR with edge-aware chrome; ABR quality selection; playback speed 0.25–2×; trick-play thumbnails from storyboard VTTs; posters until first frame; looping.

Playlists — queue videos that auto-advance, each item with its own DRM/ads/subtitle pipeline; a fully themeable “Up next” countdown card (lead time, text template, colors, font — or hidden for silent advance); skipToNext() with a dedicated skip callback so analytics can tell an impatient skip from a completed view; postrolls always finish before the queue advances. See the playlists guide.

Vertical feed — a swipeable portrait video feed as a separate surface, built on an internal pool of at most three players: neighbouring items preload muted on capped buffers for instant swipes and predictable memory. Full-page, split text + video and split video layouts; host rail actions; sponsored items; feed analytics.

DRM — Widevine + PlayReady + ClearKey (Android), FairPlay (iOS), Widevine + PlayReady + FairPlay (web); rotating token providers invoked on every license request; silent license renewal; stable 4000-series error codes.

Ads — Google IMA on all platforms, configured per media item (VAST and VMAP ad rules, skippable formats, ad-cue scrubber markers, SDK-drawn ad chrome); FreeWheel natively on Android and iOS and as VMAP-through-IMA; web ad-blocker policy (notice / hard block).

Tracks — embedded + sideloaded subtitles with positioned-cue support, custom caption fonts and viewer text sizing; multi-audio with proper display names.

Player UI — per-control visibility down to fully headless; custom controls slot; up to 8 custom action icons; full color/dimension theming and replaceable icons; themeable error overlay with custom messages in any language; fullscreen with start-in, rotation-follow and host-intercepted exit.

Overlays — nine anchored overlay slots with controls-aware choreography; Kijkwijzer-style content ratings with pluggable artwork.

Casting — Chromecast (Android), AirPlay (iOS).

Observability — identically-shaped analytics events, full ad lifecycle callbacks, and a stable 2000–9000 error taxonomy on every platform.

Licensing — fully functional unlicensed with the OGPlayer watermark; offline-verified license keys remove it.