diff --git a/pr-preview/pr-110/.nojekyll b/pr-preview/pr-110/.nojekyll
new file mode 100644
index 0000000..e69de29
diff --git a/pr-preview/pr-110/README.md b/pr-preview/pr-110/README.md
new file mode 100644
index 0000000..aba677a
--- /dev/null
+++ b/pr-preview/pr-110/README.md
@@ -0,0 +1,30 @@
+# Overview
+
+Pillarbox is a versatile media playback ecosystem engineered for Android, Apple, and Web platforms.
+
+Pillarbox is built to be adaptable and generic, ensuring it can be deployed across a variety of media applications. A
+key principle of Pillarbox is that it imposes **no user interface** constraints, empowering each product team to craft
+their own unique playback experience.
+
+It integrates seamlessly with platform features and offers robust customization options for metadata handling,
+asset management, and analytics.
+
+This page covers documentation regarding our core methodologies, cross-platform specifications, development workflows,
+and best practices.
+
+## Platform Repositories and Resources
+
+| Platform | Repository Link | Demo Link | Documentation Link |
+|------------|------------------------------------------------------------------|-------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------|
+| 🤖 Android | [pillarbox-android](https://github.com/SRGSSR/pillarbox-android) | [Demo Android](https://github.com/SRGSSR/pillarbox-android?tab=readme-ov-file#demo) | [Docs Android](https://github.com/SRGSSR/pillarbox-android?tab=readme-ov-file#integrate-pillarbox) |
+| 🍎 Apple | [pillarbox-apple](https://github.com/SRGSSR/pillarbox-apple) | [Demo Apple](https://testflight.apple.com/join/TS6ngLqf) | [Docs Apple](https://swiftpackageindex.com/SRGSSR/pillarbox-apple/3.0.0/documentation/pillarboxplayer) |
+| 🌐 Web | [pillarbox-web](https://github.com/SRGSSR/pillarbox-web) | [Demo Web](https://srgssr.github.io/pillarbox-web-demo/) | [Docs Web](https://srgssr.github.io/pillarbox-web/api/) |
+
+## Web Tools for Pillarbox
+
+`pillarbox-web` provides a set of web tools for additional functionalities to enhance the developer's experience.
+
+| Repository Link | Demo Link | Description |
+|------------------------------------------------------------------------------------|--------------------------------------------------------------|--------------------------------------------------|
+| [pillarbox-web-suite](https://github.com/SRGSSR/pillarbox-web-suite) | [Demo](https://srgssr.github.io/pillarbox-web-suite/) | A collection of plugins, themes, and components. |
+| [pillarbox-web-theme-editor](https://github.com/SRGSSR/pillarbox-web-theme-editor) | [Demo](https://srgssr.github.io/pillarbox-web-theme-editor/) | A tool for editing themes for the player. |
diff --git a/pr-preview/pr-110/_coverpage.md b/pr-preview/pr-110/_coverpage.md
new file mode 100644
index 0000000..1355549
--- /dev/null
+++ b/pr-preview/pr-110/_coverpage.md
@@ -0,0 +1,14 @@
+
+
+
+
+ Pillarbox
+
+
+> **The media player that adapts to you.**
+
+- No UI constraints, fully customizable.
+- Seamless platform integration.
+- Robust asset management and analytics.
+
+[Get Started](#overview)
diff --git a/pr-preview/pr-110/_sidebar.md b/pr-preview/pr-110/_sidebar.md
new file mode 100644
index 0000000..1e314b3
--- /dev/null
+++ b/pr-preview/pr-110/_sidebar.md
@@ -0,0 +1,15 @@
+
+ Pillarbox
+
+* [Overview](/)
+
+**Specifications**
+
+* [Monitoring](/specifications/monitoring/MONITORING.md)
+
+**Methodology**
+
+* [Definition of Done](/methodology/DEFINITION_OF_DONE.md)
+* [GitHub Projects Setup](/methodology/GITHUB_PROJECTS_SETUP.md)
+
+---
diff --git a/pr-preview/pr-110/img/pillarbox-logo.webp b/pr-preview/pr-110/img/pillarbox-logo.webp
new file mode 100644
index 0000000..65aa96f
Binary files /dev/null and b/pr-preview/pr-110/img/pillarbox-logo.webp differ
diff --git a/pr-preview/pr-110/img/srgssr-logo.png b/pr-preview/pr-110/img/srgssr-logo.png
new file mode 100644
index 0000000..79d1166
Binary files /dev/null and b/pr-preview/pr-110/img/srgssr-logo.png differ
diff --git a/pr-preview/pr-110/index.html b/pr-preview/pr-110/index.html
new file mode 100644
index 0000000..434af90
--- /dev/null
+++ b/pr-preview/pr-110/index.html
@@ -0,0 +1,61 @@
+
+
+
+
+ Pillarbox Documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pr-preview/pr-110/methodology/DEFINITION_OF_DONE.md b/pr-preview/pr-110/methodology/DEFINITION_OF_DONE.md
new file mode 100644
index 0000000..e13c543
--- /dev/null
+++ b/pr-preview/pr-110/methodology/DEFINITION_OF_DONE.md
@@ -0,0 +1,18 @@
+# Definition of Done (DoD)
+
+This document is a collaborative effort among team members to establish clear criteria for completing tasks. The DoD serves as a guide to ensure the quality and completeness of work within the team.
+
+To meet our standards, every task should adhere to the following criteria:
+
+- Code has been reviewed by at least one other team member.
+- Functionality works as expected and acceptance criteria are met.
+- Coding standards are followed.
+- No critical issues are present.
+- Performance is not compromised.
+- Unit tests pass successfully and the code successfully builds.
+- Code meets accessibility standards.
+- Code is well-documented.
+- README is updated with relevant information.
+- API documentation is updated.
+- Sensitive information is handled securely.
+- Deployment process is documented.
diff --git a/pr-preview/pr-110/methodology/GITHUB_PROJECTS_SETUP.md b/pr-preview/pr-110/methodology/GITHUB_PROJECTS_SETUP.md
new file mode 100644
index 0000000..80b8852
--- /dev/null
+++ b/pr-preview/pr-110/methodology/GITHUB_PROJECTS_SETUP.md
@@ -0,0 +1,88 @@
+# GitHub Projects Setup
+
+This article describes how we manage [our product](https://github.com/orgs/SRGSSR/projects/9) with [GitHub Projects](https://docs.github.com/en/issues/planning-and-tracking-with-projects/learning-about-projects/about-projects).
+
+## Settings
+
+We currently use 3 settings:
+
+- **Status** for the various statuses an issue might have in our workflow. Statuses must be defined in the following order so that board columns are ordered correctly:
+ - **✏️ Draft**: Tasks which have not been sufficiently refined yet.
+ - **📋 Backlog**: Tasks which are ready to be planned.
+ - **🚧 In Progress**: Tasks currently being worked on.
+ - **🍿 Code Review**: Tasks currently being reviewed.
+ - **✅ Done**: Completed tasks.
+- **Sprint**: Duration of 1 week.
+- **Platform**:
+ - **✨ All**
+ - **🤖 Android**
+ - **🍎 Apple**
+ - **🌍 Web**
+
+## Workflows
+
+Workflow management is currently limited on GitHub Projects. Here are the ones we kept and how they are set:
+
+- **Item added to project**: When an issue or pull request is added set its status to _Draft_.
+- **Item reopened**: When an issue or pull request is reopened set its status to _Backlog_.
+- **Item closed**: When an issue or pull request is closed set its status to _Done_.
+- **Pull request merged**: When a pull request is merged set its status to _Done_.
+
+## Views
+
+We have created the following views:
+
+### Sprint board
+
+Displays a board of the the current sprint:
+
+- Layout: Board
+- Fields: Title, Assignees, Status, Platform, Linked pull requests
+- Column field: Status
+- Field sum: Count
+- Sort: Manual
+- Filter: `-status:"✏️ Draft"`
+
+### Drafts
+
+Displays all issues to be refined per platform:
+
+- Layout: Table
+- Fields: Title, Milestone, Platform, Labels
+- Group: Platform
+- Field sum: Count
+- Sort: Manual
+- Filter: `status:"✏️ Draft"`
+
+### Product Backlog
+
+Displays the product backlog for all platforms:
+
+- Layout: Table
+- Fields: Title, Status, Milestone, Platform, Sprint, Labels
+- Group: Status
+- Field sum: Count
+- Sort: Status-desc
+- Filter: `status:"✏️ Draft","📋 Backlog"`
+
+### Current Milestone
+
+Displays the current milestone which represents the current focus:
+
+- Layout: Table
+- Fields: Title, Status, Platform, Sprint, Labels, Milestone
+- Group: Platform
+- Field sum: Count
+- Sort: Manual
+- Filter: `-status:"✅ Done","✏️ Draft" milestone:`
+
+### Sprint List
+
+Displays issues per sprint:
+
+- Layout: Table
+- Fields: Title, Sprint, Milestone, Platform, Status, Linked pull requests, Labels
+- Group: Sprint
+- Field sum: Count
+- Sort: Sprint-desc
+- Filter: `-no:sprint`
diff --git a/pr-preview/pr-110/specifications/monitoring/MONITORING.md b/pr-preview/pr-110/specifications/monitoring/MONITORING.md
new file mode 100644
index 0000000..f4c7e1a
--- /dev/null
+++ b/pr-preview/pr-110/specifications/monitoring/MONITORING.md
@@ -0,0 +1,365 @@
+# Monitoring Specification
+
+---
+
+**Version:** 1.0 |
+**Date:** August 19, 2024
+
+---
+
+## Introduction
+
+Pillarbox integrates with a monitoring platform that provides real-time and historical dashboards for:
+
+- Quality of Service (QoS): QoS refers to the performance level of a service, especially in terms of its transmission
+ quality and service availability.
+- Quality of Experience (QoE): QoE is a user-centric measure that evaluates the overall experience of the user with a
+ service.
+
+This article describes the flexible event model that allows our players to send data to our monitoring platform.
+
+## JSON Key / Value Naming Conventions
+
+The following naming conventions are applied for key / values appearing in JSON payloads:
+
+- Keys use snake case.
+- Values are provided in a form best suited for display, usually capitalized, with possible exceptions when brand
+ names are involved (e.g. macOS must not be capitalized as MacOS).
+- The only values provided in uppercase are event types (e.g. `START`).
+
+> [!WARNING]
+> Values provided by the system (e.g. device names) can be assumed as having a form already best suited for display.
+> Their case must not be changed.
+
+## General Event Format
+
+Events provide data related to specific points of interests in the lifetime of a playback session. Three kinds of event
+types are available:
+
+- `START`
+- `ERROR`
+- Status events (`STOP`, `HEARTBEAT`)
+
+Associated information is provided in JSON payloads all having the same fixed top-level structure containing the
+following keys:
+
+| Key | Description | Format | Examples |
+|--------------|---------------------------------------------|-----------------------------------------------------------------|----------------------------------------|
+| `data` | Data associated with the event | JSON dictionary | `{ ... }` |
+| `event_name` | The name of the event | `START`, `STOP`, `ERROR`, `HEARTBEAT` | `STOP` |
+| `session_id` | A unique identifier for the session | [UUID](https://www.itu.int/en/ITU-T/asn1/Pages/UUID/uuids.aspx) | `37b18444-76b6-4159-8539-d48ea5ecbc86` |
+| `timestamp` | The timestamp at the time the event is sent | [Unix timestamp](https://unixtime.org) in milliseconds | `1717665997932` |
+| `version` | The version of the JSON format | Number | 1 |
+
+> [!WARNING]
+> All keys listed above are mandatory.
+
+All events associated with the same session **MUST** be assigned the same `session_id`. The `data` format associated
+with each event type is described in more detail below.
+
+## Start Event `data`
+
+An event with the name `START` **MUST** be sent to signal the start of a playback session. This event conveys important
+static context information and is therefore required, no matter playback successfully starts or not:
+
+- Success: The `START` event **MUST** be sent when the player is ready to play.
+- Failure: The `START` event **MUST** be sent immediately before an `ERROR` event describing the reason for the failure.
+
+The associated event data dictionary supports the following keys:
+
+| Key | Description | Format | Examples |
+|---------------|------------------------------|-----------------|-----------|
+| `browser` | Browser information | JSON dictionary | `{ ... }` |
+| `device` | Device information | JSON dictionary | `{ ... }` |
+| `media` | Media information | JSON dictionary | `{ ... }` |
+| `os` | Operating system information | JSON dictionary | `{ ... }` |
+| `player` | Player information | JSON dictionary | `{ ... }` |
+| `screen` | Screen information | JSON dictionary | `{ ... }` |
+| `qoe_timings` | QoE timings | JSON dictionary | `{ ... }` |
+| `qos_timings` | QoS timings | JSON dictionary | `{ ... }` |
+
+> [!WARNING]
+> Requirements for each key are not provided explicitly but implementations **SHOULD** fill as much information as
+> possible. If some information cannot be reliably determined it **SHOULD** be omitted.
+
+### JSON Schema
+
+[start-schema.json](specifications/monitoring/schemas/start-schema.json ':ignore')
+
+### Browser
+
+The `browser` JSON data dictionary supports the following keys:
+
+| Field | Description | Format | Examples |
+|-----------|---------------------|--------|---------------------|
+| `name` | The browser name | String | `Firefox`, `Safari` |
+| `version` | The browser version | String | `129.0` |
+
+### Device
+
+The `device` JSON data dictionary supports the following keys:
+
+| Field | Description | Format | Examples |
+|---------|----------------------------------------------|------------------------------------------------------|----------------------------------------|
+| `id` | A unique anonymous identifier for the device | String | `105124c0-fa84-4028-908e-618f2402d46f` |
+| `model` | The device model | String | `iPhone15.7`, `Samsung Galaxy S24` |
+| `type` | The device type | `Car`, `Desktop`, `Headset`, `Phone`, `Tablet`, `TV` | `Phone` |
+
+### Media
+
+The `media` JSON data dictionary supports the following keys:
+
+| Field | Description | Format | Examples |
+|----------------|-----------------------------------------------------------|--------|------------------------------------------------------------------------------------------|
+| `asset_url` | The URL of the content being played | String | `https://...` |
+| `id` | A unique media identifier | String | `urn:rts:video:123456` |
+| `metadata_url` | The URL where media metadata was fetched | String | `https://...` |
+| `origin` | A description of the context in which the media is played | String | `ch.srgssr.app`, `https://...` |
+
+Some remarks:
+
+- Any token appended **by the client** to the URL of the asset being played **SHOULD NOT** appear in `asset_url`.
+- The `origin` is flexible but **SHOULD** describe the context of playback, for example an application identifier or the
+ URL of the web page hosting the media.
+
+### Operating System
+
+The `os` JSON data dictionary supports the following keys:
+
+| Field | Description | Format | Examples |
+|-----------|------------------------------|--------|-------------------------------|
+| `name` | The operating system name | String | `macOS`, `Windows`, `Android` |
+| `version` | The operating system version | String | `14.5` |
+
+### Player
+
+The `player` JSON data dictionary supports the following keys:
+
+| Field | Description | Format | Examples |
+|------------|---------------------|---------------------------|--------------------------------------|
+| `name` | The player name | String | `Pillarbox`, `Letterbox`, `video.js` |
+| `platform` | The player platform | `Android`, `Apple`, `Web` | `Android` |
+| `version` | The player version | String | `1.2.3` |
+
+### Quality of Experience Timings
+
+The `qoe_timings` JSON data dictionary supports the following keys:
+
+| Field | Description | Format | Examples |
+|------------|---------------------------------------------------|----------------------|----------|
+| `asset` | Time the user waited for asset playback to start | Time in milliseconds | `1145` |
+| `metadata` | Time the user waited for metadata to be retrieved | Time in milliseconds | `412` |
+| `total` | Total time the user waited for playback to start | Time in milliseconds | `1763` |
+
+> [!WARNING]
+> QoE timings measure the perceived user experience. If content preloading in a playlist makes it possible to start
+> instantaneously (or almost), these values **SHOULD** be zero or close to zero.
+
+### Quality of Service Timings
+
+The `qos_timings` JSON data dictionary supports the following keys:
+
+| Field | Description | Format | Examples |
+|------------|-------------------------------------------------|----------------------|----------|
+| `asset` | Time for the player to start playing the asset | Time in milliseconds | `1145` |
+| `drm` | Time to load DRM content keys | Time in milliseconds | `245` |
+| `metadata` | Time for metadata to be retrieved by the player | Time in milliseconds | `412` |
+| `token` | Time to fetch an authorization token | Time in milliseconds | `356` |
+
+> [!WARNING]
+> QoS timings measure actual system performance. They **SHOULD** reflect the time technically required to fetch content,
+> whether content preloading could take place or not.
+
+### Screen
+
+The `screen` JSON data dictionary supports the following keys:
+
+| Field | Description | Format | Examples |
+|----------|-----------------------------|--------|----------|
+| `height` | The screen height in pixels | Number | `2160` |
+| `width` | The screen width in pixels | Number | `3840` |
+
+### Example
+
+```json
+{
+ "data": {
+ "device": {
+ "id": "8e9242a4-60b6-48f9-8dfb-6ee43e36c7eb",
+ "model": "iPad13,4",
+ "type": "Tablet"
+ },
+ "media": {
+ "asset_url": "https://rts-vod-amd.akamaized.net/ww/14895342/85891228-1e53-371b-997a-094380f533e2/master.m3u8",
+ "id": "urn:rts:video:14895342",
+ "metadata_url": "https://il.srgssr.ch/integrationlayer/2.1/mediaComposition/byUrn/urn:rts:video:14895342?onlyChapters=true&vector=appplay",
+ "origin": "ch.srgssr.Pillarbox-demo"
+ },
+ "os": {
+ "name": "iPadOS",
+ "version": "18.0"
+ },
+ "player": {
+ "name": "Pillarbox",
+ "platform": "Apple",
+ "version": "2.0.0-49"
+ },
+ "qoe_timings": {
+ "asset": 1164,
+ "metadata": 320,
+ "total": 1484
+ },
+ "screen": {
+ "height": 2388,
+ "width": 1668
+ }
+ },
+ "event_name": "START",
+ "session_id": "ebdb3da7-bc77-454e-9de0-a1dfa8091e84",
+ "timestamp": 1723640597805,
+ "version": 1
+}
+```
+
+## Error Event `data`
+
+An event with the name `ERROR` **MUST** be sent when an error, either fatal or not, has been encountered:
+
+- A fatal error makes playback fail without the possibility to recover, either when playback is started or during
+ playback (e.g. following a network failure).
+- A non-fatal error (warning) informs about potential issues that occur behind the scenes and might affect the playback
+ experience negatively.
+
+> [!WARNING]
+> A fatal `ERROR` at startup **MUST** always be preceded by a `START` event. If playback is restarted after a fatal
+`ERROR` a new session **MUST** be created, beginning with a new `START` event.
+
+The associated event data dictionary supports the following keys:
+
+| Key | Description | Format | Examples |
+|----------------------|------------------------------------------------------------------------------------------------------|--------------------------------------------------------|---------------------------------------------------------------------------------------------|
+| `duration` | The content duration, as retrieved from the playlist | Time in milliseconds | `16548` |
+| `log` | Any additional information that might be helpful | Any | `{ ... }`, `[...]`, `Stack trace symbols: ...` |
+| `message` | The message associated with the error (might be localized) | String | `Not found` |
+| `name` | The name of the error | String | `ERR-404` |
+| `position` | The current player position, relative to the beginning of the playlist. Negative values are admitted | Time in milliseconds | `16548` |
+| `position_timestamp` | The current player timestamp, as retrieved from the playlist. Omitted if not available | [Unix timestamp](https://unixtime.org) in milliseconds | `1717665997932` |
+| `url` | The URL that was affected by the error | String | `https://...` |
+| `vpn` | A value indicating whether a VPN is enabled on the device | Boolean | `true` |
+
+> [!WARNING]
+> Requirements for each key are not provided explicitly but implementations **SHOULD** fill as much information as
+> possible. If some information cannot be reliably determined it **SHOULD** be omitted.
+
+Some remarks:
+
+- If the error occurs before playback has started (e.g. during metadata retrieval) then `position`, `player_timestamp`
+ and `duration` **MUST** be omitted.
+- The `url` **SHOULD** describe the content that was affected as closely as possible, down to media playlists or segment
+ URLs, provided this information is available.
+- The `log` is informally defined so that any useful information can be added for investigation purposes.
+
+### JSON Schema
+
+[error-schema.json](specifications/monitoring/schemas/error-schema.json ':ignore')
+
+### Example
+
+```json
+{
+ "data": {
+ "message": "Segment exceeds specified bandwidth for variant",
+ "name": "CoreMediaErrorDomain(-12318)",
+ "position": 1024,
+ "url": "https://rts-vod-amd.akamaized.net/ww/14895342/85891228-1e53-371b-997a-094380f533e2/index-f4-v1.m3u8",
+ "vpn": false
+ },
+ "event_name": "ERROR",
+ "session_id": "ebdb3da7-bc77-454e-9de0-a1dfa8091e84",
+ "timestamp": 1723640598877,
+ "version": 1
+}
+```
+
+## Status Event `data`
+
+Other events **MUST** be sent during the playback session:
+
+| Event name | Description | Time at which the event is sent |
+|-------------|-----------------------------------------|-------------------------------------------------------------------------------|
+| `STOP` | Playback ended | When playback ends normally or is interrupted |
+| `HEARTBEAT` | Informs that the session is still alive | Every 30 seconds (also when paused). First heartbeat sent right after `START` |
+
+The associated event data dictionary supports the following keys:
+
+| Key | Description | Format | Examples |
+|----------------------|------------------------------------------------------------------------------------------------------|--------------------------------------------------------|---------------------------------------------------------------------------------------------|
+| `airplay` | A value indicating whether AirPlay is currently active | Boolean | `true` |
+| `bandwidth` | Bandwidth | Number in bits per second | `4000000` |
+| `bitrate` | Bitrate of the content being played | Number in bits per second | `1000000` |
+| `buffered_duration` | Duration of the content currently available in buffer | Time in milliseconds | `12000` |
+| `duration` | The content duration, as retrieved from the playlist | Time in milliseconds | `16548` |
+| `frame_drops` | The total number of frame drops experienced during the session | Number | `12` |
+| `playback_duration` | The duration of the playback session | Time in milliseconds | `40000` |
+| `position` | The current player position, relative to the beginning of the playlist. Negative values are admitted | Time in milliseconds | `16548` |
+| `position_timestamp` | The current player timestamp, as retrieved from the playlist. Omitted if not available | [Unix timestamp](https://unixtime.org) in milliseconds | `1717665997932` |
+| `stall` | Stall information | JSON dictionary | `{ ... }` |
+| `stream_type` | Stream type | `On-demand`, `Live` | `On-demand` |
+| `url` | The URL that is being played | String | `https://...` |
+
+> [!WARNING]
+> Requirements for each key are not provided explicitly but implementations **SHOULD** fill as much information as
+> possible. If some information cannot be reliably determined it **SHOULD** be omitted.
+
+Some remarks:
+
+- The `url` **SHOULD** describe the content currently being played as closely as possible, down to media playlists or
+ segment URLs, provided this information is available.
+- The `playback_duration` **MUST** be measured in wall-clock time, independently of playback speed adjustments.
+- The `stream_type` is present in status events only, as those can more closely match potential stream type changes when
+ a live playlist is closed and turns into an on-demand one.
+
+### JSON Schema
+
+[status-schema.json](specifications/monitoring/schemas/status-schema.json ':ignore')
+
+### Stall
+
+The `stall` JSON data dictionary supports the following keys:
+
+| Field | Description | Format | Examples |
+|------------|-----------------------------------------------------------|----------------------|----------|
+| `count` | The total number of stalls experienced during the session | Number | `4` |
+| `duration` | The total duration of stalls | Time in milliseconds | `9000` |
+
+The stall duration **MUST** be measured in wall-clock time, independently of playback speed adjustments.
+
+> [!WARNING]
+> If a player is able to provide stall information, both `count` and `duration` **MUST** be supplied, even if zero.
+
+### Example
+
+```json
+{
+ "data": {
+ "airplay": false,
+ "bandwidth": 23285774,
+ "bitrate": 6129146,
+ "buffered_duration": 36000,
+ "duration": 2386040,
+ "frame_drops": 2,
+ "playback_duration": 10663,
+ "position": 10618,
+ "stall": {
+ "count": 0,
+ "duration": 0
+ },
+ "stream_type": "On-demand",
+ "url": "https://rts-vod-amd.akamaized.net/ww/14895342/85891228-1e53-371b-997a-094380f533e2/index-f5-v1.m3u8"
+ },
+ "event_name": "STOP",
+ "session_id": "ebdb3da7-bc77-454e-9de0-a1dfa8091e84",
+ "timestamp": 1723640608474,
+ "version": 1
+}
+```
diff --git a/pr-preview/pr-110/specifications/monitoring/schemas/error-schema.json b/pr-preview/pr-110/specifications/monitoring/schemas/error-schema.json
new file mode 100644
index 0000000..d9e5bba
--- /dev/null
+++ b/pr-preview/pr-110/specifications/monitoring/schemas/error-schema.json
@@ -0,0 +1,70 @@
+{
+ "$id": "https://github.com/SRGSSR/pillarbox-documentation/blob/main/Specifications/error-schema.json",
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "object",
+ "description": "Data associated with the ERROR event, containing details about the error encountered during playback.",
+ "properties": {
+ "duration": {
+ "type": "number",
+ "description": "The content duration, as retrieved from the playlist, in milliseconds."
+ },
+ "log": {
+ "description": "Any additional information that might be helpful for debugging or investigation purposes. This can be any data type, including strings, objects, or arrays.",
+ "oneOf": [
+ { "type": "string" },
+ { "type": "object" },
+ { "type": "array" }
+ ]
+ },
+ "message": {
+ "type": "string",
+ "description": "The message associated with the error, which might be localized."
+ },
+ "name": {
+ "type": "string",
+ "description": "The name or code of the error (e.g., ERR-404)."
+ },
+ "position": {
+ "type": "number",
+ "description": "The current player position relative to the beginning of the playlist, in milliseconds. Negative values are admitted."
+ },
+ "position_timestamp": {
+ "type": "integer",
+ "description": "The current player timestamp, as retrieved from the playlist, in Unix milliseconds. This field may be omitted if not available."
+ },
+ "url": {
+ "type": "string",
+ "format": "uri",
+ "description": "The URL that was affected by the error. This should describe the content that was affected as closely as possible."
+ },
+ "vpn": {
+ "type": "boolean",
+ "description": "Indicates whether a VPN is enabled on the device."
+ }
+ },
+ "required": ["message", "name"]
+ },
+ "event_name": {
+ "type": "string",
+ "enum": ["ERROR"],
+ "description": "The name of the event, which should be 'ERROR' for this schema."
+ },
+ "session_id": {
+ "type": "string",
+ "format": "uuid",
+ "description": "A unique identifier for the session."
+ },
+ "timestamp": {
+ "type": "integer",
+ "description": "The timestamp at the time the event is sent, in Unix milliseconds."
+ },
+ "version": {
+ "type": "integer",
+ "description": "The version of the JSON format."
+ }
+ },
+ "required": ["data", "event_name", "session_id", "timestamp", "version"]
+}
diff --git a/pr-preview/pr-110/specifications/monitoring/schemas/start-schema.json b/pr-preview/pr-110/specifications/monitoring/schemas/start-schema.json
new file mode 100644
index 0000000..b790ab4
--- /dev/null
+++ b/pr-preview/pr-110/specifications/monitoring/schemas/start-schema.json
@@ -0,0 +1,175 @@
+{
+ "$id": "https://github.com/SRGSSR/pillarbox-documentation/blob/main/Specifications/start-schema.json",
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "object",
+ "description": "Data associated with the START event, containing details about the device, media, player, and other relevant information.",
+ "properties": {
+ "browser": {
+ "type": "object",
+ "description": "Information about the browser being used.",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The browser name (e.g., Firefox, Safari)."
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the browser."
+ }
+ }
+ },
+ "device": {
+ "type": "object",
+ "description": "Information about the device on which the media is being played.",
+ "properties": {
+ "id": {
+ "type": "string",
+ "format": "uuid",
+ "description": "A unique anonymous identifier for the device."
+ },
+ "model": {
+ "type": "string",
+ "description": "The model of the device (e.g., iPhone15.7, Samsung Galaxy S24)."
+ },
+ "type": {
+ "type": "string",
+ "description": "The type of the device (e.g., Car, Desktop, Headset, Phone, Tablet, TV)."
+ }
+ }
+ },
+ "media": {
+ "type": "object",
+ "description": "Information about the media being played.",
+ "properties": {
+ "asset_url": {
+ "type": "string",
+ "format": "uri",
+ "description": "The URL of the content being played."
+ },
+ "id": {
+ "type": "string",
+ "description": "A unique media identifier."
+ },
+ "metadata_url": {
+ "type": "string",
+ "format": "uri",
+ "description": "The URL where media metadata was fetched."
+ },
+ "origin": {
+ "type": "string",
+ "description": "A description of the context in which the media is played (e.g., application identifier or URL of the web page hosting the media)."
+ }
+ }
+ },
+ "os": {
+ "type": "object",
+ "description": "Information about the operating system of the device.",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The operating system name (e.g., macOS, Windows, Android)."
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the operating system."
+ }
+ }
+ },
+ "player": {
+ "type": "object",
+ "description": "Information about the media player.",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the player (e.g., Pillarbox, Letterbox, video.js)."
+ },
+ "platform": {
+ "type": "string",
+ "description": "The platform on which the player is running (e.g., Android, Apple, Web)."
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the player."
+ }
+ }
+ },
+ "qoe_timings": {
+ "type": "object",
+ "description": "Quality of Experience (QoE) timings measuring the perceived user experience.",
+ "properties": {
+ "asset": {
+ "type": "number",
+ "description": "Time in milliseconds that the user waited for asset playback to start."
+ },
+ "metadata": {
+ "type": "number",
+ "description": "Time in milliseconds that the user waited for metadata to be retrieved."
+ },
+ "total": {
+ "type": "number",
+ "description": "Total time in milliseconds that the user waited for playback to start."
+ }
+ }
+ },
+ "qos_timings": {
+ "type": "object",
+ "description": "Quality of Service (QoS) timings measuring actual system performance.",
+ "properties": {
+ "asset": {
+ "type": "number",
+ "description": "Time in milliseconds for the player to start playing the asset."
+ },
+ "drm": {
+ "type": "number",
+ "description": "Time in milliseconds to load DRM content keys."
+ },
+ "metadata": {
+ "type": "number",
+ "description": "Time in milliseconds for metadata to be retrieved by the player."
+ },
+ "token": {
+ "type": "number",
+ "description": "Time in milliseconds to fetch an authorization token."
+ }
+ }
+ },
+ "screen": {
+ "type": "object",
+ "description": "Information about the screen resolution.",
+ "properties": {
+ "height": {
+ "type": "integer",
+ "description": "The screen height in pixels."
+ },
+ "width": {
+ "type": "integer",
+ "description": "The screen width in pixels."
+ }
+ }
+ }
+ }
+ },
+ "event_name": {
+ "type": "string",
+ "enum": ["START"],
+ "description": "The name of the event, which should be 'START' for this schema."
+ },
+ "session_id": {
+ "type": "string",
+ "format": "uuid",
+ "description": "A unique identifier for the session."
+ },
+ "timestamp": {
+ "type": "integer",
+ "description": "The timestamp at the time the event is sent, in Unix milliseconds."
+ },
+ "version": {
+ "type": "integer",
+ "description": "The version of the JSON format."
+ }
+ },
+ "required": ["data", "event_name", "session_id", "timestamp", "version"]
+}
diff --git a/pr-preview/pr-110/specifications/monitoring/schemas/status-schema.json b/pr-preview/pr-110/specifications/monitoring/schemas/status-schema.json
new file mode 100644
index 0000000..ea7b009
--- /dev/null
+++ b/pr-preview/pr-110/specifications/monitoring/schemas/status-schema.json
@@ -0,0 +1,89 @@
+{
+ "$id": "https://github.com/SRGSSR/pillarbox-documentation/blob/main/Specifications/status-schema.json",
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "object",
+ "description": "Data associated with the status event, containing details about the current state of playback, network, and device.",
+ "properties": {
+ "airplay": {
+ "type": "boolean",
+ "description": "Indicates whether AirPlay is currently active."
+ },
+ "bandwidth": {
+ "type": "integer",
+ "description": "The available bandwidth in bits per second."
+ },
+ "bitrate": {
+ "type": "integer",
+ "description": "The bitrate of the content being played in bits per second."
+ },
+ "buffered_duration": {
+ "type": "number",
+ "description": "The duration of the content currently available in the buffer, in milliseconds."
+ },
+ "duration": {
+ "type": "number",
+ "description": "The content duration, as retrieved from the playlist, in milliseconds."
+ },
+ "playback_duration": {
+ "type": "number",
+ "description": "The duration of the playback session in milliseconds, measured in wall-clock time."
+ },
+ "position": {
+ "type": "number",
+ "description": "The current player position relative to the beginning of the playlist, in milliseconds. Negative values are admitted."
+ },
+ "position_timestamp": {
+ "type": "integer",
+ "description": "The current player timestamp as retrieved from the playlist, in Unix milliseconds. This field may be omitted if not available."
+ },
+ "stall": {
+ "type": "object",
+ "description": "Information about playback stalls experienced during the session.",
+ "properties": {
+ "count": {
+ "type": "integer",
+ "description": "The total number of stalls experienced during the session."
+ },
+ "duration": {
+ "type": "number",
+ "description": "The total duration of stalls in milliseconds, measured in wall-clock time."
+ }
+ },
+ "required": ["count", "duration"]
+ },
+ "stream_type": {
+ "type": "string",
+ "enum": ["On-demand", "Live"],
+ "description": "The type of stream being played, either 'On-demand' or 'Live'."
+ },
+ "url": {
+ "type": "string",
+ "format": "uri",
+ "description": "The URL of the content currently being played. This should describe the content as closely as possible, including media playlists or segment URLs if available."
+ }
+ }
+ },
+ "event_name": {
+ "type": "string",
+ "enum": ["STOP", "HEARTBEAT"],
+ "description": "The name of the event, which can be either 'STOP' or 'HEARTBEAT'."
+ },
+ "session_id": {
+ "type": "string",
+ "format": "uuid",
+ "description": "A unique identifier for the session."
+ },
+ "timestamp": {
+ "type": "integer",
+ "description": "The timestamp at the time the event is sent, in Unix milliseconds."
+ },
+ "version": {
+ "type": "integer",
+ "description": "The version of the JSON format."
+ }
+ },
+ "required": ["data", "event_name", "session_id", "timestamp", "version"]
+}