From d144eb871ca76eb40ffa60143aa820a0bc155e76 Mon Sep 17 00:00:00 2001 From: Jeroen Tempels Date: Tue, 7 Apr 2026 10:07:10 +0200 Subject: [PATCH 01/15] Add note that DVR window size is set at the channel level --- theolive/channel/dvr.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/theolive/channel/dvr.mdx b/theolive/channel/dvr.mdx index 7d9e2932b6b6..ebfceff98e38 100644 --- a/theolive/channel/dvr.mdx +++ b/theolive/channel/dvr.mdx @@ -24,6 +24,8 @@ To enable DVR, set a **window size** in seconds on your channel. This determines +The DVR window size is configured at the channel level and applies equally to all distributions. You cannot set different window sizes for different distributions. However, you can enable or disable DVR on a per-distribution basis. + When DVR is enabled, viewers can scrub back through the live stream within the configured window. Once the window is exceeded, older content is no longer available for playback. ## API example From 80cd06c8c47dceecf0eab5ed46968d80a6af8e4d Mon Sep 17 00:00:00 2001 From: Jeroen Tempels Date: Tue, 7 Apr 2026 10:13:00 +0200 Subject: [PATCH 02/15] Document pull/push mode support and SRT passphrase usage --- theolive/contribution/ingest-protocols.mdx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/theolive/contribution/ingest-protocols.mdx b/theolive/contribution/ingest-protocols.mdx index cdd107611b39..679b16ac60ee 100644 --- a/theolive/contribution/ingest-protocols.mdx +++ b/theolive/contribution/ingest-protocols.mdx @@ -10,6 +10,8 @@ description: Supported ingest protocols (RTMP and SRT) and their trade-offs. The Dolby OptiView Live platform supports low latency live streaming through two ingest protocols: **RTMP** and **SRT**. +RTMP supports both **pull** and **push** mode out of the box. SRT works out of the box in **pull mode** only, where the platform connects to your encoder to pull the stream. If you need SRT push mode, contact your account representative to have it enabled. + ## RTMP — Real-Time Messaging Protocol RTMP is a widely adopted protocol originally developed by Adobe for transmitting audio, video, and data over the internet. It remains one of the most commonly supported protocols across hardware and software encoders. @@ -34,3 +36,9 @@ SRT is an open-source protocol designed for low latency, secure, and reliable vi - **Cons** - **Less universal encoder support** — While adoption is growing, not all encoders support SRT, especially older hardware models. - **More complex configuration** — SRT may require tuning parameters such as latency, overhead bandwidth, and encryption settings for optimal performance. + +### SRT passphrase + +In **pull mode**, you can secure the connection by including the passphrase directly in the SRT URL that you configure on your channel (e.g. `srt://encoder-host:port?passphrase=my-secret`). + +In **push mode**, the Dolby team configures the passphrase for you and provides an SRT URL with the passphrase included. From 546ee0c622a891dbd2d911685afb80b857b2e84a Mon Sep 17 00:00:00 2001 From: Jeroen Tempels Date: Tue, 7 Apr 2026 10:14:06 +0200 Subject: [PATCH 03/15] Add note that DRM is a fully managed premium feature --- theolive/media-engine/drm.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/theolive/media-engine/drm.mdx b/theolive/media-engine/drm.mdx index 5fac47baed56..4e4a9c600068 100644 --- a/theolive/media-engine/drm.mdx +++ b/theolive/media-engine/drm.mdx @@ -10,6 +10,10 @@ description: Protect your live streams with Digital Rights Management. Digital Rights Management (DRM) protects live video content by encrypting the stream so that only authorized viewers can watch it. Without DRM, streams can be intercepted, redistributed, or recorded without permission. +:::info +DRM is a fully managed, premium feature. Contact your account representative to learn more and get started. +::: + DRM is essential for content that requires legal or contractual protection, such as premium sports broadcasts, pay-per-view events, or licensed entertainment. It ensures that content owners retain control over who can access their streams and under what conditions. ## Enabling DRM From dc106e82459b6c39e7c9e6bb67d708c05919dcf5 Mon Sep 17 00:00:00 2001 From: Jeroen Tempels Date: Tue, 7 Apr 2026 10:20:24 +0200 Subject: [PATCH 04/15] Add some additional information --- theolive/getting-started.mdx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/theolive/getting-started.mdx b/theolive/getting-started.mdx index 607ce489c7d8..da0404acdd80 100644 --- a/theolive/getting-started.mdx +++ b/theolive/getting-started.mdx @@ -6,6 +6,8 @@ sidebar_custom_props: description: Create your first stream, from setup to embedding the player. --- +OptiView Live Streaming is the new name for THEOlive Streaming as part of the OptiView product suite. During the transition, you may still see references to THEOlive. OptiView Live and THEOlive refer to the same product. + # Getting started This guide walks you through creating your first stream, from setting up an account to embedding the player on your page. @@ -78,8 +80,8 @@ The engine is responsible for transcoding and packaging the incoming media. Crea - **Enable DRM** — secure your content with Digital Rights Management. - **Enable HESP** — output content in HESP format for low latency delivery. - **Enable HLS** — output content in HLS format for broad platform compatibility. -- **Enable HLS MPEG-TS** — output content in HLS MPEG-TS format. Only recommended for very specific platforms that don't support HLS with CMAF segments. -- **DAI Asset Key** — asset key for Dynamic Ad Insertion. +- **Enable HLS MPEG-TS** — output content in HLS MPEG-TS format. Only recommended for very specific platforms that don't support HLS with CMAF segments. This feature needs to be explicitly enabled in your account by an admin and isn't compatible with some other features like DRM. +- **DAI Asset Key** — asset key for OptiView ads. To learn more, contact your Dolby team. From e459fe75859f640766bc1b3a4c436f8d2b3dd045 Mon Sep 17 00:00:00 2001 From: Jeroen Tempels Date: Tue, 7 Apr 2026 10:24:22 +0200 Subject: [PATCH 05/15] Add viewer tracking page with tracking workflow and JWT examples --- theolive/platform/viewer-tracking.mdx | 59 +++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 theolive/platform/viewer-tracking.mdx diff --git a/theolive/platform/viewer-tracking.mdx b/theolive/platform/viewer-tracking.mdx new file mode 100644 index 000000000000..504ce5f61e17 --- /dev/null +++ b/theolive/platform/viewer-tracking.mdx @@ -0,0 +1,59 @@ +--- +sidebar_position: 8 +sidebar_label: Viewer tracking +sidebar_custom_props: + icon: 📍 +description: Track viewers and syndication partners using tracking IDs and custom viewer data. +--- + +# Viewer tracking + +You can syndicate content through multiple distribution partners while utilizing the same channel, or alternatively track different groups through distributions. This can be helpful for aggregating viewing and billing data for a group of viewers. + +Additionally, when using the advanced reporting feature, you might want to assign tracking metadata to individual viewers to post-process later in your data and BI analysis tools. This is all possible with our viewer tracking workflows. + +## Tracking workflow + +The following is an example workflow for setting up stream tracking: + +1. Create a channel. +2. Enable [token security](../distribution/security/token-based-security.mdx) on the channel or alias. +3. When you create your self-signed token, add one or both of the following parameters to a `streaming` object in the payload of your JWT: + - **`trackingId`** — Groups viewers of the same channel, allows you to get the aggregated bandwidth usage of all viewers. This is useful for billing a single channel or alias if you use multiple distribution partners and want aggregated billing metrics back or viewer reports for groups of viewers. The maximum size is 128 characters. + - **`customViewerData`** — Access the bandwidth consumption of each viewer for analytics purposes and pass through metadata from your CMS for a viewer and be able to retrieve it in a viewer report. This data is not parsed by our system and can be a series of key-value pairs for you to extract later. The maximum size is 1024 characters. +4. Pass the JWT through to the player as described in the [token security](../distribution/security/token-based-security.mdx) section. +5. To get Advanced Reports, including user-reports, please contact your Dolby representative for access. + +:::note +Either or both `trackingId` and/or `customViewerData` may be used depending on what kind of tracking you need to achieve. +::: + +Here is an example `payload` for a JWT that includes sample `trackingId` and `customViewerData`: + +```json +{ + "streaming": { + "tracking": { + "trackingId": "groupAbc" + }, + "customViewerData": "user=user123;appVersion=x.y.x", + "tokenType": "Subscribe" + }, + "iat": 1750813271, + "exp": 1750813871 +} +``` + +Here is the JWT that is generated from this payload. You can paste it into [jwt.io](https://jwt.io/) to inspect it: + +``` +eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdHJlYW1pbmciOnsidHJhY2tpbmciOnsidHJhY2tpbmdJZCI6Imdyb3VwQWJjIn0sImN1c3RvbVZpZXdlckRhdGEiOiJ1c2VyPXVzZXIxMjM7YXBwVmVyc2lvbj14LnkueCIsInRva2VuVHlwZSI6IlN1YnNjcmliZSJ9LCJpYXQiOjE3NTA4MTMyNzEsImV4cCI6MTc1MDgxMzg3MX0.OvIZAvs6XL4KQ8YTtIdjdJNZ5oS6Jkosj3mq274gdrw +``` + +To validate the token, use the following secret: `d2e166fdda89824a6c493d8a2af7a0754199eff9e38c579cba8783767a44039c`. + +### Notes + +- Tracking can be used independently of secure channels. You can pass the same payload parameters in a JWT, however, the token must be "valid" — the required date fields must be valid or the token will be ignored. If a channel does not have token security enabled, be aware that anyone can view the channel with or without a JWT. Without secure channels, the signature is not validated, so there is a risk that a user could change the values. +- If you are combining the OptiView real-time streaming solution and the live streaming solution, you may use the secret from the real-time subscriber token as the secret you provide to OptiView live streaming and use the same JWTs across both streaming products. +- `tokenType` should be set to `Subscribe`. From 6721f4607fcd9f14afce42080610556d8aa04e64 Mon Sep 17 00:00:00 2001 From: Jeroen Tempels Date: Tue, 7 Apr 2026 10:36:17 +0200 Subject: [PATCH 06/15] Add dashboard section with screenshot to image overlays page --- theolive/assets/img/image-overlays.png | Bin 0 -> 41735 bytes theolive/media-engine/image-overlays.mdx | 8 ++++++++ 2 files changed, 8 insertions(+) create mode 100644 theolive/assets/img/image-overlays.png diff --git a/theolive/assets/img/image-overlays.png b/theolive/assets/img/image-overlays.png new file mode 100644 index 0000000000000000000000000000000000000000..2568723d5d52f747bc98f40c13bff559d839428a GIT binary patch literal 41735 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%0A#q~lYzLoLZDsdFP_yV;h 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 jbX Date: Tue, 7 Apr 2026 11:19:09 +0200 Subject: [PATCH 07/15] Update changelog through PR instead of pre-built --- .../workflows/update-theolive-changelog.yml | 71 +++++++++++++++++++ .gitignore | 1 - package.json | 4 +- theolive/changelog.md | 25 +++++++ 4 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/update-theolive-changelog.yml create mode 100644 theolive/changelog.md diff --git a/.github/workflows/update-theolive-changelog.yml b/.github/workflows/update-theolive-changelog.yml new file mode 100644 index 000000000000..66d3c7ef1fe4 --- /dev/null +++ b/.github/workflows/update-theolive-changelog.yml @@ -0,0 +1,71 @@ +name: Update THEOlive changelog +on: + # Runs every hour + schedule: + - cron: '0 * * * *' + workflow_dispatch: +jobs: + update: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + env: + # The branch that will receive the changelog update (will be created if it doesn't exist) + # Will automatically open a new PR (if no PR exists yet) + UPDATE_BRANCH: update-theolive-changelog + steps: + - name: Create app token + uses: actions/create-github-app-token@v3 + id: app-token + with: + app-id: ${{ vars.THEOPLAYER_BOT_APP_ID }} + private-key: ${{ secrets.THEOPLAYER_BOT_PRIVATE_KEY }} + - name: Checkout + uses: actions/checkout@v6 + with: + token: ${{ steps.app-token.outputs.token }} + fetch-depth: 1 + - name: Configure Git user + run: | + git config user.name 'theoplayer-bot[bot]' + git config user.email '873105+theoplayer-bot[bot]@users.noreply.github.com' + - name: Fetch THEOlive changelog + run: | + curl -fsSL -o theolive/changelog.md \ + 'https://engine-changelog.s3.eu-west-3.amazonaws.com/CHANGELOG.md' + - name: Check for changes + id: check_changes + run: | + if git diff --quiet theolive/changelog.md; then + echo "No changelog changes detected." + else + echo "changed=true" >> "$GITHUB_OUTPUT" + fi + - name: Commit and push changes + if: ${{ steps.check_changes.outputs.changed }} + run: | + git checkout -b $UPDATE_BRANCH + git add theolive/changelog.md + git commit -m 'Update THEOlive changelog' + git push --force origin HEAD:$UPDATE_BRANCH + - name: Check if pull request already exists + if: ${{ steps.check_changes.outputs.changed }} + id: check_pr_exists + run: | + pr_count=$(gh pr list --base main --head "$UPDATE_BRANCH" --state open --limit 1 --json number --jq length) + if ((pr_count > 0)); then + echo "exists=true" >> "$GITHUB_OUTPUT" + fi + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + - name: Create pull request + if: ${{ steps.check_changes.outputs.changed && !steps.check_pr_exists.outputs.exists }} + run: | + gh pr create \ + --base main \ + --head "$UPDATE_BRANCH" \ + --title "Update THEOlive changelog" \ + --body "This PR pulls in the latest THEOlive engine changelog." + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} diff --git a/.gitignore b/.gitignore index a90a143b2321..ab474137bea2 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,6 @@ .docusaurus .cache-loader static/theoplayer-license.txt -theolive/changelog.md # Misc .DS_Store diff --git a/package.json b/package.json index a14a2a83fe73..ec302114a863 100644 --- a/package.json +++ b/package.json @@ -5,9 +5,9 @@ "scripts": { "docusaurus": "docusaurus", "start": "docusaurus start", - "prestart": "npm run gen-api-docs && npm run fetch-theolive-changelog", + "prestart": "npm run gen-api-docs", "build": "docusaurus build", - "prebuild": "npm run gen-api-docs && npm run fetch-theolive-changelog", + "prebuild": "npm run gen-api-docs", "swizzle": "docusaurus swizzle", "clear": "docusaurus clear", "serve": "node serve.js", diff --git a/theolive/changelog.md b/theolive/changelog.md new file mode 100644 index 000000000000..75dbf4e57427 --- /dev/null +++ b/theolive/changelog.md @@ -0,0 +1,25 @@ +# Changelog + +## [10.13.0] - 2026-03-25 + +- Added image overlay support +- Upgraded to GStreamer 1.28.1 +- Upgraded to Rust 1.94 + +## [10.12.0] - 2026-03-06 + +- Optimized encode of HLS when HESP is disabled +- Allow enabling / disabling of individual protocols +- Improved quality of de-interlacing +- Improved quality of video scaler +- Upgraded to GStreamer 1.28 +- Simplified stream config +- VMAF +- eRTMP built-in from GStreamer +- Improved logging +- Disable PlayReady +- Deprecate /streams + +## [10.9.0] - 2026-01-30 + +- Initial changelog From 5c37262152844b1426fc61353e6266064086d8e1 Mon Sep 17 00:00:00 2001 From: Jeroen Tempels Date: Tue, 7 Apr 2026 13:41:39 +0200 Subject: [PATCH 08/15] Remove unused changelog script --- package.json | 1 - scripts/fetch-theolive-changelog.mjs | 22 ---------------------- 2 files changed, 23 deletions(-) delete mode 100644 scripts/fetch-theolive-changelog.mjs diff --git a/package.json b/package.json index ec302114a863..eca1017a6ae0 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,6 @@ "serve": "node serve.js", "write-translations": "docusaurus write-translations", "write-heading-ids": "docusaurus write-heading-ids", - "fetch-theolive-changelog": "node scripts/fetch-theolive-changelog.mjs", "gen-api-docs": "docusaurus gen-api-docs all --plugin-id ads-api && docusaurus gen-api-docs all --plugin-id ad-engine-api && docusaurus gen-api-docs all --plugin-id millicast-api && docusaurus gen-api-docs all --plugin-id theolive-api --all-versions", "clean-api-docs": "docusaurus clean-api-docs all --plugin-id ads-api && docusaurus clean-api-docs all --plugin-id ad-engine-api && docusaurus clean-api-docs all --plugin-id millicast-api && docusaurus clean-api-docs all --plugin-id theolive-api --all-versions", "typecheck": "tsc", diff --git a/scripts/fetch-theolive-changelog.mjs b/scripts/fetch-theolive-changelog.mjs deleted file mode 100644 index db8108deb159..000000000000 --- a/scripts/fetch-theolive-changelog.mjs +++ /dev/null @@ -1,22 +0,0 @@ -import fs from 'fs'; -import path from 'path'; -import { fileURLToPath } from 'url'; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const url = 'https://engine-changelog.s3.eu-west-3.amazonaws.com/CHANGELOG.md'; -const outputPath = path.join(__dirname, '..', 'theolive', 'changelog.md'); - -try { - const response = await fetch(url); - if (!response.ok) { - throw new Error(`Failed to fetch changelog: ${response.status} ${response.statusText}`); - } - const content = await response.text(); - fs.writeFileSync(outputPath, content); - console.log('Fetched THEOlive engine changelog.'); -} catch (error) { - console.warn(`Warning: Could not fetch THEOlive engine changelog: ${error.message}`); - if (!fs.existsSync(outputPath)) { - fs.writeFileSync(outputPath, '# Changelog\n\nChangelog could not be fetched.\n'); - } -} From a14567750663d9b2110a2b9505fd66cfdff52b84 Mon Sep 17 00:00:00 2001 From: jeroentempels-dolby Date: Wed, 8 Apr 2026 09:23:54 +0200 Subject: [PATCH 09/15] Update viewer tracking text to match example Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- theolive/platform/viewer-tracking.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/theolive/platform/viewer-tracking.mdx b/theolive/platform/viewer-tracking.mdx index 504ce5f61e17..ad58b66f8897 100644 --- a/theolive/platform/viewer-tracking.mdx +++ b/theolive/platform/viewer-tracking.mdx @@ -18,8 +18,8 @@ The following is an example workflow for setting up stream tracking: 1. Create a channel. 2. Enable [token security](../distribution/security/token-based-security.mdx) on the channel or alias. -3. When you create your self-signed token, add one or both of the following parameters to a `streaming` object in the payload of your JWT: - - **`trackingId`** — Groups viewers of the same channel, allows you to get the aggregated bandwidth usage of all viewers. This is useful for billing a single channel or alias if you use multiple distribution partners and want aggregated billing metrics back or viewer reports for groups of viewers. The maximum size is 128 characters. +3. When you create your self-signed token, add one or both of the following parameters to the `streaming` object in the payload of your JWT: + - **`tracking.trackingId`** — Groups viewers of the same channel, allows you to get the aggregated bandwidth usage of all viewers. This is useful for billing a single channel or alias if you use multiple distribution partners and want aggregated billing metrics back or viewer reports for groups of viewers. The maximum size is 128 characters. - **`customViewerData`** — Access the bandwidth consumption of each viewer for analytics purposes and pass through metadata from your CMS for a viewer and be able to retrieve it in a viewer report. This data is not parsed by our system and can be a series of key-value pairs for you to extract later. The maximum size is 1024 characters. 4. Pass the JWT through to the player as described in the [token security](../distribution/security/token-based-security.mdx) section. 5. To get Advanced Reports, including user-reports, please contact your Dolby representative for access. From 94113735d5a2ca029b6a6239312d1a8bb3c152a3 Mon Sep 17 00:00:00 2001 From: Jeroen Tempels Date: Wed, 8 Apr 2026 09:53:09 +0200 Subject: [PATCH 10/15] Add API reference links to webhook documentation --- .../platform/real-time-update-with-webhooks.mdx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/theolive/platform/real-time-update-with-webhooks.mdx b/theolive/platform/real-time-update-with-webhooks.mdx index 04ee3d26b311..f6b39cd84519 100644 --- a/theolive/platform/real-time-update-with-webhooks.mdx +++ b/theolive/platform/real-time-update-with-webhooks.mdx @@ -10,6 +10,8 @@ description: Receive real-time notifications when channel events occur. Webhooks let you receive real-time notifications when events happen in your streaming infrastructure. Instead of polling for changes, you register an endpoint URL and the system pushes event data to it automatically. +For the full endpoint specification, see the [Webhooks API reference](../api/create-webhook.api.mdx). + ## What is a Webhook? A webhook is an HTTP callback that sends a `POST` request to your endpoint whenever a subscribed event occurs — for example, when a channel starts, an engine encounters an error, or a distribution is updated. @@ -102,7 +104,7 @@ You can also use the **wildcard** (`*`) to listen to all events at once. After creation, you are redirected to the webhook detail page where you can view the signing secret. -### API example — Create a webhook +### API example — [Create a webhook](../api/create-webhook.api.mdx) **Listen to specific events:** @@ -138,7 +140,7 @@ The **Webhooks** page shows a table of all your webhooks with: - **Events** — Shows "All events" for wildcard webhooks, or the count of subscribed events. - **Actions** — Edit or delete the webhook. -### API example — List all webhooks +### API example — [List all webhooks](../api/get-webhooks.api.mdx) `GET https://api.theo.live/v2/webhooks` @@ -149,7 +151,7 @@ Optional query parameters: | `cursor` | [Pagination](../api/pagination.mdx) cursor for the next page | | `limit` | Number of results per page | -### API example — Get a single webhook +### API example — [Get a single webhook](../api/get-webhook.api.mdx) `GET https://api.theo.live/v2/webhooks/{webhookId}` @@ -186,7 +188,7 @@ You can change: Click **Save** to apply your changes. -### API example — Update a webhook +### API example — [Update a webhook](../api/update-webhook.api.mdx) All fields are optional; only include the fields you want to change. @@ -209,7 +211,7 @@ When editing a webhook, you can toggle the **Active / Inactive** switch. This is useful when you want to temporarily stop receiving events without deleting the webhook. -### API example — Activate or deactivate a webhook +### API example — [Activate or deactivate a webhook](../api/update-webhook.api.mdx) Use the update endpoint with the `active` field: @@ -229,7 +231,7 @@ Click the **trash icon** on the webhooks list, or click **Delete** on the webhoo > **Note:** You must deactivate a webhook before deleting it. -### API example — Delete a webhook +### API example — [Delete a webhook](../api/delete-webhook.api.mdx) `DELETE https://api.theo.live/v2/webhooks/{webhookId}` @@ -331,7 +333,7 @@ app.listen(port, () => { }); ``` -### API example — Get the webhook secret +### API example — [Get the webhook secret](../api/get-webhook-secret.api.mdx) `GET https://api.theo.live/v2/webhooks/{webhookId}/secret` From 54ef573c97b91368e24384ea10abcc77465ab9f7 Mon Sep 17 00:00:00 2001 From: Jeroen Tempels Date: Wed, 8 Apr 2026 10:00:29 +0200 Subject: [PATCH 11/15] Add channel overview description to generated-index page --- sidebarsTheolive.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sidebarsTheolive.ts b/sidebarsTheolive.ts index 5026e893467f..e603227fdb5f 100644 --- a/sidebarsTheolive.ts +++ b/sidebarsTheolive.ts @@ -14,7 +14,12 @@ const sidebars: SidebarsConfig = { icon: '📺', }, description: 'Configure channel-level settings and optional features.', - link: { type: 'generated-index', slug: 'channel' }, + link: { + type: 'generated-index', + slug: 'channel', + description: + 'A channel is the core building block of the platform — it represents a complete live streaming pipeline from media ingestion through to viewer delivery. Each channel is composed of ingests, engines, and distributions. This section covers settings configured at the channel level. See the Architecture page for the full breakdown.', + }, items: [{ type: 'autogenerated', dirName: 'channel' }], }, { From 68b306ab278181e622ccdf118947e472edcc111a Mon Sep 17 00:00:00 2001 From: Jeroen Tempels Date: Wed, 8 Apr 2026 10:02:54 +0200 Subject: [PATCH 12/15] Add DVR distribution enablement note and large window caution --- theolive/channel/dvr.mdx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/theolive/channel/dvr.mdx b/theolive/channel/dvr.mdx index ebfceff98e38..768fe03bc1be 100644 --- a/theolive/channel/dvr.mdx +++ b/theolive/channel/dvr.mdx @@ -26,8 +26,16 @@ To enable DVR, set a **window size** in seconds on your channel. This determines The DVR window size is configured at the channel level and applies equally to all distributions. You cannot set different window sizes for different distributions. However, you can enable or disable DVR on a per-distribution basis. +In addition to setting the window size on the channel, DVR must also be **enabled on each distribution** where you want viewers to have time-shifted playback. Distributions without DVR enabled will serve a live-only stream, even if the channel has a DVR window configured. + When DVR is enabled, viewers can scrub back through the live stream within the configured window. Once the window is exceeded, older content is no longer available for playback. +:::caution[Large DVR windows] +Very large DVR windows produce large HLS/DASH playlists, which can result in degraded performance on some players and devices. Chromecasts in particular are known to have issues with long DVR windows. + +If you need a long DVR window, test thoroughly on your target devices before going to production. +::: + ## API example You can also enable DVR via the API by setting `dvr.enabled` to `true` and `dvr.windowInSeconds` to your desired window size (60–86400 seconds) when [creating](../api/create-channel.api.mdx) or [updating](../api/update-channel.api.mdx) your channel. From 35d800f3329797f0d1a5525f87b15bebe31afd64 Mon Sep 17 00:00:00 2001 From: Jeroen Tempels Date: Wed, 8 Apr 2026 10:09:17 +0200 Subject: [PATCH 13/15] Align HLS latency values to 8s+ across all pages --- theolive/media-engine/encoding-quality.mdx | 2 +- theolive/media-engine/streaming-protocols.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/theolive/media-engine/encoding-quality.mdx b/theolive/media-engine/encoding-quality.mdx index f3671e7bbf19..8d062af17a3d 100644 --- a/theolive/media-engine/encoding-quality.mdx +++ b/theolive/media-engine/encoding-quality.mdx @@ -25,7 +25,7 @@ If low latency is not a requirement for your use case, configure your engine to | Use case | Recommended outputs | Latency | Image quality | | ---------------------------------------------- | ------------------- | ----------------- | ------------- | | Live sports betting, interactive entertainment | HESP + HLS | Ultra-low (1–5s) | Good | -| Linear broadcast, non-interactive live events | HLS only | Standard (10–30s) | Higher | +| Linear broadcast, non-interactive live events | HLS only | Standard (8s+) | Higher | :::tip You can create multiple engines on the same channel with different output configurations. For example, use one engine with HESP for low-latency viewers and another with HLS only for viewers who prioritize quality over latency. Attach each to a separate distribution to serve both audiences from the same ingest. diff --git a/theolive/media-engine/streaming-protocols.mdx b/theolive/media-engine/streaming-protocols.mdx index aa4bce0fde4c..5cd91e52aba6 100644 --- a/theolive/media-engine/streaming-protocols.mdx +++ b/theolive/media-engine/streaming-protocols.mdx @@ -22,7 +22,7 @@ HESP is a next-generation streaming protocol designed for ultra-low latency live HLS is the industry-standard protocol developed by Apple for delivering live and on-demand content over HTTP. The media engine outputs HLS using modern CMAF (fragmented MP4) segments. - **Broad compatibility** — supported by virtually all modern browsers, devices and players. -- **Higher latency** — compared to HESP, HLS typically introduces several seconds of additional latency. +- **Higher latency** — HLS typically delivers latency of 8 seconds or more, compared to 1–5 seconds with HESP. ### HLS (MPEG-TS) From fb32109fe8868071bd308d778c246c69c28a88bb Mon Sep 17 00:00:00 2001 From: Jeroen Tempels Date: Wed, 8 Apr 2026 10:15:42 +0200 Subject: [PATCH 14/15] Fix prettier formatting --- theolive/media-engine/encoding-quality.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/theolive/media-engine/encoding-quality.mdx b/theolive/media-engine/encoding-quality.mdx index 8d062af17a3d..ad9afa9e8550 100644 --- a/theolive/media-engine/encoding-quality.mdx +++ b/theolive/media-engine/encoding-quality.mdx @@ -22,10 +22,10 @@ If low latency is not a requirement for your use case, configure your engine to ## Choosing the right configuration -| Use case | Recommended outputs | Latency | Image quality | -| ---------------------------------------------- | ------------------- | ----------------- | ------------- | -| Live sports betting, interactive entertainment | HESP + HLS | Ultra-low (1–5s) | Good | -| Linear broadcast, non-interactive live events | HLS only | Standard (8s+) | Higher | +| Use case | Recommended outputs | Latency | Image quality | +| ---------------------------------------------- | ------------------- | ---------------- | ------------- | +| Live sports betting, interactive entertainment | HESP + HLS | Ultra-low (1–5s) | Good | +| Linear broadcast, non-interactive live events | HLS only | Standard (8s+) | Higher | :::tip You can create multiple engines on the same channel with different output configurations. For example, use one engine with HESP for low-latency viewers and another with HLS only for viewers who prioritize quality over latency. Attach each to a separate distribution to serve both audiences from the same ingest. From 97e08dace86bfeeca02131c0d7ae477057831098 Mon Sep 17 00:00:00 2001 From: TimLeenaers Date: Wed, 8 Apr 2026 10:39:01 +0200 Subject: [PATCH 15/15] update webhooks guide: describe right request body --- .../real-time-update-with-webhooks.mdx | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/theolive/platform/real-time-update-with-webhooks.mdx b/theolive/platform/real-time-update-with-webhooks.mdx index f6b39cd84519..379004641f92 100644 --- a/theolive/platform/real-time-update-with-webhooks.mdx +++ b/theolive/platform/real-time-update-with-webhooks.mdx @@ -242,22 +242,30 @@ When an event fires, Dolby sends a `POST` request to your endpoint with a JSON b ```json { "type": "channel.stopped", - "created": 1711900800, + "createdAt": 1711900800, "object": { "type": "channel", - "id": "ch_abc123" + "id": "ch_abc123", + "name": "name-of-channel", + "organizationId": "organization-id", + // optionally information about the parent object (id, type and name) }, - "data": { ... } + "data": { ... }, } ``` -| Field | Description | -| ------------- | ------------------------------------------------------------------------------ | -| `type` | The event type string (e.g. `channel.stopped`, `engine.error`) | -| `created` | Unix timestamp of when the event occurred | -| `object.type` | The resource type: `channel`, `engine`, `ingest`, `distribution`, or `webhook` | -| `object.id` | The ID of the resource that triggered the event | -| `data` | Event-specific payload with additional details | +| Field | Description | +| ----------------------- | ------------------------------------------------------------------------------ | +| `type` | The event type string (e.g. `channel.stopped`, `engine.error`) | +| `createdAt` | Unix timestamp of when the event occurred | +| `object.type` | The resource type: `channel`, `engine`, `ingest`, `distribution`, or `webhook` | +| `object.id` | The ID of the resource that triggered the event | +| `object.name` | The name of the resource that triggered the event | +| `object.organizationId` | The ID of the organization that owns the resource | +| `object.parent.id` | Optionally: the ID of the parent resource that triggered the event | +| `object.parent.name` | Optionally: the name of the parent resource that triggered the event | +| `object.parent.type` | Optionally: the type of the parent resource that triggered the event | +| `data` | Event-specific payload with additional details | ## Verifying Webhook Signatures