diff --git a/.editorconfig b/.editorconfig index bf6ea1d..1758c7b 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,7 +7,8 @@ end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true +indent_style=space +indent_size=4 -[*.{md}] -indent_style = space -indent_size = 4 +[*.md] +max_line_length = 120 diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..434d5f1 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @MGaetan89 @StaehliJ @amtins @defagos @jboix @waliid diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 4774315..204fd72 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,7 +1,12 @@ -# Description +## Description -> Describe enhancements with sufficient details. +> Please provide a brief summary of the changes made. Include the specific guideline that is being +> addressed or added, and explain its significance. -# Changes made +> Please explain why this change was necessary. Was there a lack of clarity? Was the information +> outdated? Or is this a new addition to the guidelines? -> Please list the specific changes made in this pull request. +## Changes Made + +> Please detail the modifications made. This could include areas such as changes in content, +> structure, or formatting. diff --git a/.github/workflows/github-page.yml b/.github/workflows/github-page.yml new file mode 100644 index 0000000..b47931b --- /dev/null +++ b/.github/workflows/github-page.yml @@ -0,0 +1,22 @@ +name: Github Page + +on: + push: + branches: + - main + +jobs: + github-page: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Deploy GitHub Page 🚀 + uses: JamesIves/github-pages-deploy-action@releases/v4 + with: + branch: gh-pages + folder: public + force: false + clean-exclude: pr-preview/ diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml new file mode 100644 index 0000000..1e47ec3 --- /dev/null +++ b/.github/workflows/preview.yml @@ -0,0 +1,25 @@ +name: Deploy PR previews + +on: + pull_request: + types: + - opened + - reopened + - synchronize + - closed + +concurrency: preview-${{ github.ref }} + +jobs: + deploy-preview: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Deploy Preview 🚀 + uses: rossjrw/pr-preview-action@v1 + with: + source-dir: public + preview-branch: gh-pages + umbrella-dir: pr-preview diff --git a/.gitignore b/.gitignore index 496ee2c..cf03057 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,8 @@ -.DS_Store \ No newline at end of file +### Intellij ### +.idea + +### VisualStudioCode ### +.vscode + +# macOs +.DS_Store diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..958b27e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) SRG SSR + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md deleted file mode 100644 index fee9f69..0000000 --- a/README.md +++ /dev/null @@ -1,10 +0,0 @@ - -[![Pillarbox logo](README-images/logo.jpg)](https://github.com/SRGSSR/pillarbox-documentation) - -# About - -Cross-platform documentation for Pillarbox, the modern SRG SSR player ecosystem. - -# Articles - -- [GitHub Projects Setup](GITHUB_PROJECTS_SETUP.md) diff --git a/Specifications/monitoring.md b/Specifications/monitoring.md deleted file mode 100644 index a027227..0000000 --- a/Specifications/monitoring.md +++ /dev/null @@ -1,316 +0,0 @@ -# Monitoring - -- Version: 1 - -## 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. - -## 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 | - -> [!IMPORTANT] -> 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 | `{ ... }` | - -> [!IMPORTANT] -> 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. - -### 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://rts1-lsvs.akamaized.net/out/v1/62441d2399f14dce9e558b5503edba11/index.m3u8` | -| `id` | A unique media identifier | String | `urn:rts:video:123456` | -| `metadata_url` | The URL where media metadata was fetched | String | `https://il.srgssr.ch/integrationlayer/2.0/mediaComposition/byUrn/urn:rts:video:3608506` | -| `origin` | A description of the context in which the media is played | String | `ch.srgssr.app`, `https://www.rts.ch/info/article/123` | - -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` | - -> [!IMPORTANT] -> 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` | - -> [!IMPORTANT] -> 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_metrics": { - "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. - -> [!IMPORTANT] -> 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` | -| `severity` | The error severity | `WARNING`, `FATAL` | `WARNING` | -| `url` | The URL that was affected by the error | String | `https://rts1-lsvs.akamaized.net/out/v1/62441d2399f14dce9e558b5503edba11/index_1_948290.ts` | - -> [!IMPORTANT] -> 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. - -### Example - -```json -{ - "data": { - "message": "Segment exceeds specified bandwidth for variant", - "name": "CoreMediaErrorDomain(-12318)", - "position": 1024, - "severity": "WARNING", - "url": "https://rts-vod-amd.akamaized.net/ww/14895342/85891228-1e53-371b-997a-094380f533e2/index-f4-v1.m3u8" - }, - "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` | -| `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://rts1-lsvs.akamaized.net/out/v1/62441d2399f14dce9e558b5503edba11/index_1_948290.ts` | -| `vpn` | A value indicating whether a VPN is enabled on the device | Boolean | `true` | - -> [!IMPORTANT] -> 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. - -### 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. - -> [!IMPORTANT] -> 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, - "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", - "vpn": false - }, - "event_name": "STOP", - "session_id": "ebdb3da7-bc77-454e-9de0-a1dfa8091e84", - "timestamp": 1723640608474, - "version": 1 -} -``` diff --git a/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..baa8507 --- /dev/null +++ b/docs/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md new file mode 100644 index 0000000..c201ae7 --- /dev/null +++ b/docs/CONTRIBUTING.md @@ -0,0 +1,41 @@ +# Contributing + +Thank you very much for your interest in contributing to our project! As a public service company, we want to shape a product that better matches our user needs and desires. Ideas or direct contributions are therefore warmly welcome and will be considered with great care, provided they fulfill a few requirements listed in this document. Please read it first before you decide to contribute. + +## Purpose + +Our development team is small, our ability to quickly evaluate a need or a code submission is therefore critical. Please follow the present contributing guidelines so that we can efficiently consider your proposal. You should also read or our [code of conduct](CODE_OF_CONDUCT.md), providing a few guidelines to keep interactions as respectful as possible. + +## Contributions we are looking for + +Any kind of contribution is welcome, as long as it improves the overall quality of our product, for example: + +* Requests for new features or ideas. +* Bug reports or fixes. +* Documentation improvements. +* Translation improvements. + +Contributions can either take the form of simple issues where you describe the problem you face or what you would like to see in our products. If you feel up to the challenge, you can even submit code in the form of pull requests which our team will review. + +## Contributions we are not looking for + +Requests which are too vague or not related to our product will not be taken into account. We also have no editorial influence, any issue related to the content available on our platform will simply be closed. + +## Making a contribution + +You can use issues to report bugs, submit ideas or request features. People with a programming background can also submit changes directly via pull requests. Creating issues or pull requests requires you to own or [open](https://github.com/join) a GitHub account. + +If you are not sure about the likelihood of a change you propose to be accepted, please open an issue first. We can discuss it there, especially whether it is compatible with our product or not. This way you can avoid creating an entire pull request we will never be able to merge. + +Templates are available when you want to contribute: + +* [Issues](https://github.com/SRGSSR/pillarbox-documentation/issues/new): Please follow our issue template. You can omit information which does not make sense but, in general, the more details you can provide, the better. This ensures we can quickly reproduce the problem you are facing, increasing the likelihood we can fix it. +* [Pull requests](https://github.com/SRGSSR/pillarbox-documentation/compare): Please follow our code conventions, test your code well, and write unit tests when this makes sense. We will review your work and, if successful, merge it back into the main development branch. + +## Code conventions + +We currently have no formal code conventions, but we try to keep our codebase consistent. In general, having a look at the code itself should be enough for you to discover how you should write your changes. + +## Code review + +Pull requests, once complete, can be submitted for review by our team. Depending on the complexity of the involved changes, a few iterations might be needed. Once a pull request has been approved, it will be rebased, merged back into the development trunk and delivered with the next release. diff --git a/README-images/logo.jpg b/docs/README-images/logo.jpg similarity index 100% rename from README-images/logo.jpg rename to docs/README-images/logo.jpg diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..ed0f603 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,42 @@ + +[![Pillarbox logo](README-images/logo.jpg)](https://github.com/SRGSSR/pillarbox-documentation) + +This repository provides comprehensive documentation and specifications for the Pillarbox player product, which +supports Android, Apple, and Web platforms. + +Our goal is to ensure that developers and stakeholders have access to clear and detailed guidelines to facilitate the +successful implementation and integration of Pillarbox across various projects. + +To access the documentation, please visit: [Pillarbox Documentation][pillarbox-docs]. + +## How to Contribute + +We welcome contributions from everyone. The site is hosted on GitHub Pages and is powered by [docsify][docsify], served +from the [public](../public) folder in this repository. + +Here's a brief overview of the project structure: + +- [public](../public): This directory serves as the homepage for the docsify site and contains all the documentation + files written in markdown. +- [public/_sidebar.md](../public/_sidebar.md): This markdown file renders the sidebar of the page. Add links to your + documentation sections here. + +To create a new section or document, simply add a file under [public](../public) and include a link to it in +the [_sidebar.md](../public/_sidebar.md) file. + +> [!TIP] +> To test the site, simply open [public/index.html](../public/index.html) on your project. + +Please adhere to our [Contribution Guidelines](./CONTRIBUTING.md) when making a contribution. + +Feel free to [open issues][open-issues], [submit pull requests][submit-pr], or [share your ideas][discussions]. + +## License + +For more information, please refer to the [LICENSE](../LICENSE) file. + +[docsify]: https://docsify.js.org/ +[pillarbox-docs]: https://srgssr.github.io/pillarbox-documentation +[open-issues]: https://github.com/srgssr/pillarbox-documentation/issues/new +[submit-pr]: https://github.com/srgssr/pillarbox-documentation/compare +[discussions]: https://github.com/srgssr/pillarbox-documentation/discussions diff --git a/public/.nojekyll b/public/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/public/README.md b/public/README.md new file mode 100644 index 0000000..aba677a --- /dev/null +++ b/public/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/public/_coverpage.md b/public/_coverpage.md new file mode 100644 index 0000000..1355549 --- /dev/null +++ b/public/_coverpage.md @@ -0,0 +1,14 @@ + + +

+ logo + 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/public/_sidebar.md b/public/_sidebar.md new file mode 100644 index 0000000..1e314b3 --- /dev/null +++ b/public/_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/public/img/pillarbox-logo.webp b/public/img/pillarbox-logo.webp new file mode 100644 index 0000000..65aa96f Binary files /dev/null and b/public/img/pillarbox-logo.webp differ diff --git a/public/img/srgssr-logo.png b/public/img/srgssr-logo.png new file mode 100644 index 0000000..79d1166 Binary files /dev/null and b/public/img/srgssr-logo.png differ diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..434af90 --- /dev/null +++ b/public/index.html @@ -0,0 +1,61 @@ + + + + + Pillarbox Documentation + + + + + + + + + + + +
+ + + + + + + + + + + + diff --git a/DEFINITION_OF_DONE.md b/public/methodology/DEFINITION_OF_DONE.md similarity index 100% rename from DEFINITION_OF_DONE.md rename to public/methodology/DEFINITION_OF_DONE.md diff --git a/GITHUB_PROJECTS_SETUP.md b/public/methodology/GITHUB_PROJECTS_SETUP.md similarity index 100% rename from GITHUB_PROJECTS_SETUP.md rename to public/methodology/GITHUB_PROJECTS_SETUP.md diff --git a/public/specifications/monitoring/MONITORING.md b/public/specifications/monitoring/MONITORING.md new file mode 100644 index 0000000..b85e727 --- /dev/null +++ b/public/specifications/monitoring/MONITORING.md @@ -0,0 +1,352 @@ +# 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. + +## 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 | + +> [!ATTENTION] +> 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 | `{ ... }` | + +> [!ATTENTION] +> 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` | + +> [!ATTENTION] +> 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` | + +> [!ATTENTION] +> 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_metrics": { + "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. + +> [!ATTENTION] +> 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` | +| `severity` | The error severity | `WARNING`, `FATAL` | `WARNING` | +| `url` | The URL that was affected by the error | String | `https://...` | + +> [!ATTENTION] +> 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, + "severity": "WARNING", + "url": "https://rts-vod-amd.akamaized.net/ww/14895342/85891228-1e53-371b-997a-094380f533e2/index-f4-v1.m3u8" + }, + "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` | +| `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://...` | +| `vpn` | A value indicating whether a VPN is enabled on the device | Boolean | `true` | + +> [!ATTENTION] +> 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. + +> [!ATTENTION] +> 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, + "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", + "vpn": false + }, + "event_name": "STOP", + "session_id": "ebdb3da7-bc77-454e-9de0-a1dfa8091e84", + "timestamp": 1723640608474, + "version": 1 +} +``` diff --git a/public/specifications/monitoring/schemas/error-schema.json b/public/specifications/monitoring/schemas/error-schema.json new file mode 100644 index 0000000..52d3d31 --- /dev/null +++ b/public/specifications/monitoring/schemas/error-schema.json @@ -0,0 +1,71 @@ +{ + "$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." + }, + "severity": { + "type": "string", + "enum": ["WARNING", "FATAL"], + "description": "The severity of the error." + }, + "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." + } + }, + "required": ["message", "name", "severity"] + }, + "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/public/specifications/monitoring/schemas/start-schema.json b/public/specifications/monitoring/schemas/start-schema.json new file mode 100644 index 0000000..b790ab4 --- /dev/null +++ b/public/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/public/specifications/monitoring/schemas/status-schema.json b/public/specifications/monitoring/schemas/status-schema.json new file mode 100644 index 0000000..692806e --- /dev/null +++ b/public/specifications/monitoring/schemas/status-schema.json @@ -0,0 +1,93 @@ +{ + "$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." + }, + "vpn": { + "type": "boolean", + "description": "Indicates whether a VPN is enabled on the device." + } + } + }, + "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"] +}