├── .gitattributes ├── .github └── workflows │ └── auto-publish.yml ├── .gitignore ├── .pr-preview.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.md ├── Makefile ├── README.md ├── application.bs ├── application_messages.cddl ├── archive ├── control_protocol.md ├── datachannel.md ├── j-pake.md ├── mdns.md ├── quic.md ├── ssdp.md └── templates │ ├── README.md │ ├── discovery.md │ └── transport.md ├── benchmarks ├── README.md ├── discovery.md └── transport.md ├── biblio.json ├── capabilities.md ├── code-style.html ├── device_specs.md ├── explainer.md ├── images ├── entire_flow_chart.svg ├── mdns.png ├── schemes.png └── ssdp.png ├── index.bs ├── messages_appendix.cddl ├── network.bs ├── network_messages.cddl ├── requirements.md ├── schemes.md ├── scripts ├── __init__.py ├── cddl_lexer.py ├── openscreen_cddl_dfns.py └── pygmentize_dir.py └── w3c.json /.gitattributes: -------------------------------------------------------------------------------- 1 | index.html merge=binary 2 | *_appendix.html merge=binary 3 | 4 | -------------------------------------------------------------------------------- /.github/workflows/auto-publish.yml: -------------------------------------------------------------------------------- 1 | # Workflow based on the main w3c/spec-prod action example: 2 | # https://github.com/w3c/spec-prod/#basic-usage 3 | # 4 | # Custom code added to generate the CDDL messages appendix for inclusion in the 5 | # generated specification file. 6 | 7 | name: Build, Validate, and Deploy 8 | 9 | on: 10 | # Worflow runs on pull requests where it makes sure that the spec can still be 11 | # generated, that markup is valid and that there are no broken links, as 12 | # well as on pushes to the default branch where it also deploys the generated 13 | # spec to the gh-pages branch. The "workflow_dispatch" hook allows admins to 14 | # also trigger the workflow manually from GitHub's UI. 15 | pull_request: {} 16 | push: 17 | branches: [main] 18 | workflow_dispatch: 19 | 20 | jobs: 21 | main: 22 | runs-on: ubuntu-latest 23 | steps: 24 | # See doc at https://github.com/actions/checkout/ 25 | - name: Checkout repository 26 | uses: actions/checkout@v4 27 | 28 | # See doc at https://github.com/actions/setup-python/ 29 | - name: Setup Python 30 | uses: actions/setup-python@v5 31 | with: 32 | python-version: 3.9 33 | 34 | - name: Install Python dependencies 35 | run: | 36 | python -m pip install --upgrade pip 37 | pip install Pygments 38 | 39 | # Note: the step actually generates all CDDL message pages, but the 40 | # w3c/spec-prod action cleans these files after each build, so we'll 41 | # have to generate them again each time. 42 | - name: Generate messages_appendix.html 43 | run: python scripts/pygmentize_dir.py 44 | 45 | # See doc at https://github.com/w3c/spec-prod/#spec-prod 46 | # The action only deploys the generated spec to the gh-pages branch when 47 | # the workflow was triggered by a push to the default branch. 48 | - name: Build and validate index.html, push to gh-pages branch if needed 49 | uses: w3c/spec-prod@v2 50 | with: 51 | GH_PAGES_BRANCH: gh-pages 52 | 53 | - name: Generate application_messages.html 54 | run: python scripts/pygmentize_dir.py 55 | 56 | - name: Build and validate application.html, push to gh-pages branch if needed 57 | uses: w3c/spec-prod@v2 58 | with: 59 | SOURCE: application.bs 60 | TOOLCHAIN: bikeshed 61 | GH_PAGES_BRANCH: gh-pages 62 | W3C_ECHIDNA_TOKEN: ${{ secrets.ECHIDNA_TOKEN_APPLICATION }} 63 | W3C_WG_DECISION_URL: https://lists.w3.org/Archives/Public/public-secondscreen/2022Apr/0007.html 64 | W3C_BUILD_OVERRIDE: | 65 | status: WD 66 | 67 | - name: Generate network_messages.html 68 | run: python scripts/pygmentize_dir.py 69 | 70 | - name: Build and validate network.html, push to gh-pages branch if needed 71 | uses: w3c/spec-prod@v2 72 | with: 73 | SOURCE: network.bs 74 | TOOLCHAIN: bikeshed 75 | GH_PAGES_BRANCH: gh-pages 76 | W3C_ECHIDNA_TOKEN: ${{ secrets.ECHIDNA_TOKEN_NETWORK }} 77 | W3C_WG_DECISION_URL: https://lists.w3.org/Archives/Public/public-secondscreen/2022Apr/0007.html 78 | W3C_BUILD_OVERRIDE: | 79 | status: WD 80 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | index.html 3 | messages_appendix.html 4 | application.html 5 | application_messages.html 6 | network.html 7 | network_messages.html 8 | 9 | -------------------------------------------------------------------------------- /.pr-preview.json: -------------------------------------------------------------------------------- 1 | { 2 | "src_file": "index.bs", 3 | "type": "bikeshed", 4 | "params": { 5 | "force": 1 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | All documentation, code and communication under this repository are covered by the [W3C Code of Ethics and Professional Conduct](https://www.w3.org/Consortium/cepc/). 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Please refer to the group's [Work Mode](https://www.w3.org/wiki/Second_Screen/Work_Mode). 4 | 5 | Contributions to this repository are intended to become part of Recommendation-track documents governed by the 6 | [W3C Patent Policy](http://www.w3.org/Consortium/Patent-Policy-20040205/) and 7 | [Software and Document License](http://www.w3.org/Consortium/Legal/copyright-software). 8 | To make substantive contributions to specifications, you must either participate 9 | in the relevant W3C Working Group or make a non-member patent licensing commitment. 10 | 11 | If you are not the sole contributor to a contribution (pull request), please identify all 12 | contributors in the pull request comment. 13 | 14 | To add a contributor (other than yourself, that's automatic), mark them one per line as follows: 15 | 16 | ``` 17 | +@github_username 18 | ``` 19 | 20 | If you added a contributor by mistake, you can remove them in a comment with: 21 | 22 | ``` 23 | -@github_username 24 | ``` 25 | 26 | If you are making a pull request on behalf of someone else but you had no part in designing the 27 | feature, you can remove yourself with the above syntax. 28 | 29 | 30 | ## Bikeshed 31 | 32 | The Open Screen Protocol spec is maintained with 33 | [Bikeshed](https://tabatkins.github.io/bikeshed/), which has instructions for 34 | installing the necessary tools on common platforms, and the document syntax 35 | based on Markdown. 36 | 37 | Things you can do: 38 | 39 | * `make lint` checks the input document for errors. 40 | * `make watch` runs in the background and regenerates `index.html` immediately 41 | after you modify `index.bs`. 42 | 43 | ## Using GitHub 44 | 45 | Direct contributions to the spec should be made using the [Fork & 46 | Pull](https://help.github.com/articles/using-pull-requests/#fork--pull) 47 | model. The `openscreenprotocol` directory contains the spec source `index.bs`, 48 | the messages definition `messages_appendix.cddl`, and a `Makefile` to generate 49 | the spec. 50 | 51 | 1. Before doing any local changes, it is a good idea to ensure your fork is up-to-date with the upstream repository: 52 | ```bash 53 | git fetch upstream 54 | git merge upstream/main 55 | ``` 56 | 1. In the `openscreenprotocol` directory, update the spec source `index.bs` with your changes. 57 | 1. Review your changes and commit them locally: 58 | ```bash 59 | git diff 60 | git add index.bs 61 | git commit -m "Your commit message" 62 | ``` 63 | [How to write a Git commit message](http://chris.beams.io/posts/git-commit/) 64 | 1. Push your changes up to your GitHub fork, assuming `YOUR_FORK_NAME` is the name of your remote, and you are working off of the default `main` branch: 65 | ```bash 66 | git push YOUR_FORK_NAME main 67 | ``` 68 | Note: use the default `main` branch for minor changes only. For more significant 69 | changes, please create a new branch instead. 70 | 1. On GitHub, navigate to your fork `https://github.com/YOUR_GITHUB_USERNAME/openscreenprotocol` 71 | and create a pull request with your changes. 72 | 1. Assuming there are no concerns from the group in a reasonable time, the editor 73 | will merge the changes to the upstream `webscreens/openscreenprotocol` repository, 74 | and the Editor's Draft hosted at https://webscreens.github.io/openscreenprotocol/ 75 | is automatically updated. 76 | 1. Pull requests sometimes contain work-in-progress commits such as "fix typos" or 77 | "oops" commits, that do not need to be included in the Git history of the main 78 | branch. By default, the editor will merge such pull requests with the Squash and 79 | merge option provided by GitHub to create only one commit in the Git history. 80 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | All documents in this Repository are licensed by contributors under the [W3C 2 | Software and Document License](http://www.w3.org/Consortium/Legal/copyright-software). -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BIKESHED ?= bikeshed 2 | BIKESHED_ARGS ?= --print=plain 3 | 4 | .PHONY: lint watch watch-app watch-net all 5 | 6 | # TODO: Generalize targets to reduce duplication. 7 | 8 | all: index.html application.html network.html 9 | 10 | index.html: index.bs messages_appendix.html 11 | $(BIKESHED) $(BIKESHED_ARGS) spec $< 12 | 13 | application.html: application.bs application_messages.html 14 | $(BIKESHED) $(BIKESHED_ARGS) spec $< 15 | 16 | network.html: network.bs network_messages.html 17 | $(BIKESHED) $(BIKESHED_ARGS) spec $< 18 | 19 | messages_appendix.html: messages_appendix.cddl scripts/pygmentize_dir.py scripts/cddl_lexer.py scripts/openscreen_cddl_dfns.py 20 | ./scripts/pygmentize_dir.py 21 | 22 | application_messages.html: application_messages.cddl scripts/pygmentize_dir.py scripts/cddl_lexer.py scripts/openscreen_cddl_dfns.py 23 | ./scripts/pygmentize_dir.py 24 | 25 | network_messages.html: network_messages.cddl scripts/pygmentize_dir.py scripts/cddl_lexer.py scripts/openscreen_cddl_dfns.py 26 | ./scripts/pygmentize_dir.py 27 | 28 | lint: index.bs 29 | $(BIKESHED) $(BIKESHED_ARGS) --dry-run --force spec --line-numbers $< 30 | 31 | watch: index.bs 32 | @echo 'Browse to file://${PWD}/index.html' 33 | $(BIKESHED) $(BIKESHED_ARGS) watch $< 34 | 35 | watch-app: application.bs 36 | @echo 'Browse to file://${PWD}/application.html' 37 | $(BIKESHED) $(BIKESHED_ARGS) watch $< 38 | 39 | watch-net: network.bs 40 | @echo 'Browse to file://${PWD}/network.html' 41 | $(BIKESHED) $(BIKESHED_ARGS) watch $< 42 | 43 | 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Open Screen Protocol 2 | 3 | This repository is used to develop 4 | the [Open Screen Application Protocol](https://www.w3.org/TR/openscreen-application/) 5 | and [Open Screen Network Protocol](https://www.w3.org/TR/openscreen-network/), a suite of 6 | network protocols that allow user agents to implement the [Presentation 7 | API](https://www.w3.org/TR/presentation-api/) and [Remote Playback 8 | API](https://www.w3.org/TR/remote-playback/) in an interoperable fashion. 9 | 10 | The [explainer](explainer.md) goes into more depth regarding the motivation, and 11 | rationale, and design choices for the protocol. 12 | 13 | This work is in scope for the [W3C Second Screen Working 14 | Group](https://www.w3.org/2014/secondscreen/) 15 | ([Charter](https://www.w3.org/2024/05/charter-secondscreen-wg.html)). 16 | 17 | Please refer to the group's [Work 18 | Mode](https://www.w3.org/wiki/Second_Screen/Work_Mode) for instructions on how 19 | to contribute. 20 | 21 | The protocol will meet the [functional and non-functional 22 | requirements](requirements.md) of the respective APIs as well as [hardware 23 | requirements](device_specs.md) for prospective implementations. 24 | 25 | ### Status 26 | 27 | The protocol is considered to be complete for the requirements above. It will 28 | be published as a First Public Working Draft in mid-March 2021. The remaining 29 | issues on the draft are tagged 30 | [_v1-spec_](https://github.com/w3c/openscreenprotocol/labels/v1-spec) in GitHub 31 | and noted [inline in the 32 | spec](https://w3c.github.io/openscreenprotocol/#issues-index). 33 | 34 | ### Related technologies 35 | 36 | The Open Screen Protocol is built on the following standardized technologies: 37 | 38 | - [mDNS](https://tools.ietf.org/html/rfc6762)/[DNS-SD](https://tools.ietf.org/html/rfc6763) 39 | to allow networked devices that support OSP (Open Screen agents) to discover 40 | each other; 41 | - [TLS 1.3](https://tools.ietf.org/html/rfc8446) and a Password-Authenticated 42 | Key Exchange 43 | ([PAKE](https://datatracker.ietf.org/doc/draft-irtf-cfrg-spake2/)) to create a 44 | secure channel between agents; 45 | - [QUIC](https://datatracker.ietf.org/doc/draft-ietf-quic-transport/) to 46 | transport data and media between agents; 47 | - [CBOR](https://tools.ietf.org/html/rfc8949) to encode structured data and 48 | media on-the-wire. 49 | 50 | ### Background Information 51 | 52 | The excellent [Discovery and Pairing Literature 53 | Review](https://github.com/bbc/device-discovery-pairing/blob/master/document.md) 54 | by [@chrisn](https://github.com/chrisn) and 55 | [@libbymiller](https://github.com/libbymiller) covers a wide range of existing 56 | technologies for ad-hoc interconnection among networked devices, including 57 | mDNS/DNS-SD and SSDP. 58 | -------------------------------------------------------------------------------- /application_messages.cddl: -------------------------------------------------------------------------------- 1 | ; type key 10 2 | agent-info-request = { 3 | request 4 | } 5 | 6 | ; type key 11 7 | agent-info-response = { 8 | response 9 | 1: agent-info ; agent-info 10 | } 11 | 12 | ; type key 120 13 | agent-info-event = { 14 | 0: agent-info ; agent-info 15 | } 16 | 17 | agent-capability = &( 18 | receive-audio: 1 19 | receive-video: 2 20 | receive-presentation: 3 21 | control-presentation: 4 22 | receive-remote-playback: 5 23 | control-remote-playback: 6 24 | receive-streaming: 7 25 | send-streaming: 8 26 | ) 27 | 28 | agent-info = { 29 | 0: text ; display-name 30 | 1: text ; model-name 31 | 2: [* agent-capability] ; capabilities 32 | 3: text ; state-token 33 | 4: [* text] ; locales 34 | } 35 | 36 | ; type key 12 37 | agent-status-request = { 38 | request 39 | ? 1: status ; status 40 | } 41 | 42 | ; type key 13 43 | agent-status-response = { 44 | response 45 | ? 1: status ; status 46 | } 47 | 48 | status = { 49 | 0: text ; status 50 | } 51 | 52 | request = ( 53 | 0: request-id ; request-id 54 | ) 55 | 56 | response = ( 57 | 0: request-id ; request-id 58 | ) 59 | 60 | request-id = uint 61 | 62 | microseconds = uint 63 | 64 | epoch-time = int 65 | 66 | media-timeline = float64 67 | 68 | media-timeline-range = [ 69 | start: media-timeline 70 | end: media-timeline 71 | ] 72 | 73 | watch-id = uint 74 | 75 | ; type key 14 76 | presentation-url-availability-request = { 77 | request 78 | 1: [1* text] ; urls 79 | 2: microseconds ; watch-duration 80 | 3: watch-id ; watch-id 81 | } 82 | 83 | ; type key 15 84 | presentation-url-availability-response = { 85 | response 86 | 1: [1* url-availability] ; url-availabilities 87 | } 88 | 89 | ; type key 103 90 | presentation-url-availability-event = { 91 | 0: watch-id ; watch-id 92 | 1: [1* url-availability] ; url-availabilities 93 | } 94 | 95 | ; idea: use HTTP response codes? 96 | url-availability = &( 97 | available: 0 98 | unavailable: 1 99 | invalid: 10 100 | ) 101 | 102 | ; type key 104 103 | presentation-start-request = { 104 | request 105 | 1: text ; presentation-id 106 | 2: text ; url 107 | 3: [* http-header] ; headers 108 | } 109 | 110 | http-header = [ 111 | key: text 112 | value: text 113 | ] 114 | 115 | ; type key 105 116 | presentation-start-response = { 117 | response 118 | 1: &result ; result 119 | 2: uint ; connection-id 120 | ? 3: uint ; http-response-code 121 | } 122 | 123 | presentation-termination-source = &( 124 | controller: 1 125 | receiver: 2 126 | unknown: 255 127 | ) 128 | 129 | presentation-termination-reason = &( 130 | application-request: 1 131 | user-request: 2 132 | receiver-replaced-presentation: 20 133 | receiver-idle-too-long: 30 134 | receiver-attempted-to-navigate: 31 135 | receiver-powering-down: 100 136 | receiver-error: 101 137 | unknown: 255 138 | ) 139 | 140 | ; type key 106 141 | presentation-termination-request = { 142 | request 143 | 1: text ; presentation-id 144 | 2: presentation-termination-reason ; reason 145 | } 146 | 147 | ; type key 107 148 | presentation-termination-response = { 149 | response 150 | 1: &result ; result 151 | } 152 | 153 | ; type key 108 154 | presentation-termination-event = { 155 | 0: text ; presentation-id 156 | 1: presentation-termination-source ; source 157 | 2: presentation-termination-reason ; reason 158 | } 159 | 160 | ; type key 109 161 | presentation-connection-open-request = { 162 | request 163 | 1: text ; presentation-id 164 | 2: text ; url 165 | } 166 | 167 | ; type key 110 168 | presentation-connection-open-response = { 169 | response 170 | 1: &result ; result 171 | 2: uint ; connection-id 172 | 3: uint ; connection-count 173 | } 174 | 175 | ; type key 113 176 | presentation-connection-close-event = { 177 | 0: uint ; connection-id 178 | 1: &( 179 | close-method-called: 1 180 | connection-object-discarded: 10 181 | unrecoverable-error-while-sending-or-receiving-message: 100 182 | ) ; reason 183 | ? 2: text ; error-message 184 | 3: uint ; connection-count 185 | } 186 | 187 | ; type key 121 188 | presentation-change-event = { 189 | 0: text ; presentation-id 190 | 1: uint ; connection-count 191 | } 192 | 193 | ; type key 16 194 | presentation-connection-message = { 195 | 0: uint ; connection-id 196 | 1: bytes / text ; message 197 | } 198 | 199 | result = ( 200 | success: 1 201 | invalid-url: 10 202 | invalid-presentation-id: 11 203 | timeout: 100 204 | transient-error: 101 205 | permanent-error: 102 206 | terminating: 103 207 | unknown-error: 199 208 | ) 209 | 210 | ; type key 17 211 | remote-playback-availability-request = { 212 | request 213 | 1: [* remote-playback-source] ; sources 214 | 2: microseconds ; watch-duration 215 | 3: watch-id ; watch-id 216 | } 217 | 218 | ; type key 18 219 | remote-playback-availability-response = { 220 | response 221 | 1: [* url-availability] ; url-availabilities 222 | } 223 | 224 | ; type key 114 225 | remote-playback-availability-event = { 226 | 0: watch-id ; watch-id 227 | 1: [* url-availability] ; url-availabilities 228 | } 229 | 230 | ; type key 115 231 | remote-playback-start-request = { 232 | request 233 | 1: remote-playback-id ; remote-playback-id 234 | ? 2: [* remote-playback-source] ; sources 235 | ? 3: [* text] ; text-track-urls 236 | ? 4: [* http-header] ; headers 237 | ? 5: remote-playback-controls ; controls 238 | ? 6: {streaming-session-start-request-params} ; remoting 239 | } 240 | 241 | remote-playback-source = { 242 | 0: text; url 243 | 1: text; extended-mime-type 244 | } 245 | 246 | ; type key 116 247 | remote-playback-start-response = { 248 | response 249 | ? 1: remote-playback-state ; state 250 | ? 2: {streaming-session-start-response-params} ; remoting 251 | } 252 | 253 | ; type key 117 254 | remote-playback-termination-request = { 255 | request 256 | 1: remote-playback-id ; remote-playback-id 257 | 2: &( 258 | user-terminated-via-controller: 11 259 | unknown: 255 260 | ) ; reason 261 | } 262 | 263 | ; type key 118 264 | remote-playback-termination-response = { 265 | response 266 | 1: &result ; result 267 | } 268 | 269 | ; type key 119 270 | remote-playback-termination-event = { 271 | 0: remote-playback-id ; remote-playback-id 272 | 1: &( 273 | receiver-called-terminate: 1 274 | user-terminated-via-receiver: 2 275 | receiver-idle-too-long: 30 276 | receiver-powering-down: 100 277 | receiver-crashed: 101 278 | unknown: 255 279 | ) ; reason 280 | } 281 | 282 | ; type key 19 283 | remote-playback-modify-request = { 284 | request 285 | 1: remote-playback-id ; remote-playback-id 286 | 2: remote-playback-controls ; controls 287 | } 288 | 289 | ; type key 20 290 | remote-playback-modify-response = { 291 | response 292 | 1: &result ; result 293 | ? 2: remote-playback-state ; state 294 | } 295 | 296 | ; type key 21 297 | remote-playback-state-event = { 298 | 0: remote-playback-id ; remote-playback-id 299 | 1: remote-playback-state ; state 300 | } 301 | 302 | remote-playback-id = uint 303 | 304 | remote-playback-controls = { 305 | ? 0: remote-playback-source ; source 306 | ? 1: &( 307 | none: 0 308 | metadata: 1 309 | auto: 2 310 | ) ; preload 311 | ? 2: bool ; loop 312 | ? 3: bool ; paused 313 | ? 4: bool ; muted 314 | ? 5: float64 ; volume 315 | ? 6: media-timeline ; seek 316 | ? 7: media-timeline ; fast-seek 317 | ? 8: float64 ; playback-rate 318 | ? 9: text ; poster 319 | ? 10: [* text] ; enabled-audio-track-ids 320 | ? 11: text ; selected-video-track-id 321 | ? 12: [* added-text-track] ; added-text-tracks 322 | ? 13: [* changed-text-track] ; changed-text-tracks 323 | } 324 | 325 | remote-playback-state = { 326 | ? 0: { 327 | 0: bool ; rate 328 | 1: bool ; preload 329 | 2: bool ; poster 330 | 3: bool ; added-text-track 331 | 4: bool ; added-cues 332 | } ; supports 333 | ? 1: remote-playback-source ; source 334 | ? 2: &( 335 | empty: 0 336 | idle: 1 337 | loading: 2 338 | no-source: 3 339 | ) ; loading 340 | ? 3: &( 341 | nothing: 0 342 | metadata: 1 343 | current: 2 344 | future: 3 345 | enough: 4 346 | ) ; loaded 347 | ? 4: media-error ; error 348 | ? 5: epoch-time / null ; epoch 349 | ? 6: media-timeline / null ; duration 350 | ? 7: [* media-timeline-range] ; buffered-time-ranges 351 | ? 8: [* media-timeline-range] ; seekable-time-ranges 352 | ? 9: [* media-timeline-range] ; played-time-ranges 353 | ? 10: media-timeline ; position 354 | ? 11: float64 ; playbackRate 355 | ? 12: bool ; paused 356 | ? 13: bool ; seeking 357 | ? 14: bool ; stalled 358 | ? 15: bool ; ended 359 | ? 16: float64 ; volume 360 | ? 17: bool ; muted 361 | ? 18: video-resolution / null ; resolution 362 | ? 19: [* audio-track-state] ; audio-tracks 363 | ? 20: [* video-track-state] ; video-tracks 364 | ? 21: [* text-track-state] ; text-tracks 365 | } 366 | 367 | added-text-track = { 368 | 0: &( 369 | subtitles: 1 370 | captions: 2 371 | descriptions: 3 372 | chapters: 4 373 | metadata: 5 374 | ) ; kind 375 | ? 1: text ; label 376 | ? 2: text ; language 377 | } 378 | 379 | changed-text-track = { 380 | 0: text ; id 381 | 1: text-track-mode ; mode 382 | ? 2: [* text-track-cue] ; added-cues 383 | ? 3: [* text] ; removed-cue-ids 384 | } 385 | 386 | text-track-mode = &( 387 | disabled: 1 388 | showing: 2 389 | hidden: 3 390 | ) 391 | 392 | text-track-cue = { 393 | 0: text ; id 394 | 1: media-timeline-range ; range 395 | 2: text ; text 396 | } 397 | 398 | media-sync-time = [ 399 | value: uint 400 | scale: uint 401 | ] 402 | 403 | media-error = [ 404 | code: &( 405 | user-aborted: 1 406 | network-error: 2 407 | decode-error: 3 408 | source-not-supported: 4 409 | unknown-error: 5 410 | ) 411 | message: text 412 | ] 413 | 414 | track-state = ( 415 | 0: text ; id 416 | 1: text ; label 417 | 2: text ; language 418 | ) 419 | 420 | audio-track-state = { 421 | track-state 422 | 3: bool ; enabled 423 | } 424 | 425 | video-track-state = { 426 | track-state 427 | 3: bool ; selected 428 | } 429 | 430 | text-track-state = { 431 | track-state 432 | 3: text-track-mode ; mode 433 | } 434 | 435 | ; type key 22 436 | audio-frame = [ 437 | encoding-id: uint 438 | start-time: uint 439 | payload: bytes 440 | ? optional: { 441 | ? 0: uint ; duration 442 | ? 1: media-sync-time ; sync-time 443 | } 444 | ] 445 | 446 | ; type key 23 447 | video-frame = { 448 | 0: uint ; encoding-id 449 | 1: uint ; sequence-number 450 | ? 2: [* int] ; depends-on 451 | 3: uint ; start-time 452 | ? 4: uint ; duration 453 | 5: bytes ; payload 454 | ? 6: uint ; video-rotation 455 | ? 7: media-sync-time ; sync-time 456 | } 457 | 458 | ; type key 24 459 | data-frame = { 460 | 0: uint ; encoding-id 461 | ? 1: uint ; sequence-number 462 | ? 2: uint ; start-time 463 | ? 3: uint ; duration 464 | 4: bytes ; payload 465 | ? 5: media-sync-time ; sync-time 466 | } 467 | 468 | ratio = [ 469 | antecedent: uint 470 | consequent: uint 471 | ] 472 | 473 | ; type key 122 474 | streaming-capabilities-request = { 475 | request 476 | } 477 | 478 | ; type key 123 479 | streaming-capabilities-response = { 480 | response 481 | 1: streaming-capabilities ; streaming-capabilities 482 | } 483 | 484 | streaming-capabilities = { 485 | 0: [* receive-audio-capability] ; receive-audio 486 | 1: [* receive-video-capability] ; receive-video 487 | 2: [* receive-data-capability] ; receive-data 488 | } 489 | 490 | format = { 491 | 0: text ; codec-name 492 | } 493 | 494 | receive-audio-capability = { 495 | 0: format ; codec 496 | ? 1: uint ; max-audio-channels 497 | ? 2: uint ; min-bit-rate 498 | } 499 | 500 | video-resolution = { 501 | 0: uint ; height 502 | 1: uint ; width 503 | } 504 | 505 | video-hdr-format = { 506 | 0: text; transfer-function 507 | ? 1: text; hdr-metadata 508 | } 509 | 510 | receive-video-capability = { 511 | 0: format ; codec 512 | ? 1: video-resolution ; max-resolution 513 | ? 2: ratio ; max-frames-per-second 514 | ? 3: uint ; max-pixels-per-second 515 | ? 4: uint ; min-bit-rate 516 | ? 5: ratio ; aspect-ratio 517 | ? 6: text ; color-gamut 518 | ? 7: [* video-resolution] ; native-resolutions 519 | ? 8: bool ; supports-scaling 520 | ? 9: bool ; supports-rotation 521 | ? 10: [* video-hdr-format] ; hdr-formats 522 | } 523 | 524 | receive-data-capability = { 525 | 0: format ; data-type 526 | } 527 | 528 | ; type key 124 529 | streaming-session-start-request = { 530 | request 531 | streaming-session-start-request-params 532 | } 533 | 534 | ; type key 125 535 | streaming-session-start-response = { 536 | response 537 | streaming-session-start-response-params 538 | } 539 | 540 | ; A separate group so it can be used in remote-playback-start-request 541 | streaming-session-start-request-params = ( 542 | 1: uint ; streaming-session-id 543 | 2: [* media-stream-offer] ; stream-offers 544 | 3: microseconds ; desired-stats-interval 545 | ) 546 | 547 | ; type key 126 548 | streaming-session-modify-request = { 549 | request 550 | streaming-session-modify-request-params 551 | } 552 | 553 | ; A separate group so it can be used in remote-playback-start-response 554 | streaming-session-start-response-params = ( 555 | 1: &result ; result 556 | 2: [* media-stream-request] ; stream-requests 557 | 3: microseconds ; desired-stats-interval 558 | ) 559 | 560 | streaming-session-modify-request-params = ( 561 | 1: uint ; streaming-session-id 562 | 2: [* media-stream-request] ; stream-requests 563 | ) 564 | 565 | ; type key 127 566 | streaming-session-modify-response = { 567 | response 568 | 1: &result ; result 569 | } 570 | 571 | ; type key 128 572 | streaming-session-terminate-request = { 573 | request 574 | 1: uint ; streaming-session-id 575 | } 576 | 577 | ; type key 129 578 | streaming-session-terminate-response = { 579 | response 580 | } 581 | 582 | ; type key 130 583 | streaming-session-terminate-event = { 584 | 0: uint ; streaming-session-id 585 | } 586 | 587 | media-stream-offer = { 588 | 0: uint ; media-stream-id 589 | ? 1: text ; display-name 590 | ? 2: [1* audio-encoding-offer] ; audio 591 | ? 3: [1* video-encoding-offer] ; video 592 | ? 4: [1* data-encoding-offer] ; data 593 | } 594 | 595 | media-stream-request = { 596 | 0: uint ; media-stream-id 597 | ? 1: audio-encoding-request ; audio 598 | ? 2: video-encoding-request ; video 599 | ? 3: data-encoding-request ; data 600 | } 601 | 602 | audio-encoding-offer = { 603 | 0: uint ; encoding-id 604 | 1: text ; codec-name 605 | 2: uint ; time-scale 606 | ? 3: uint ; default-duration 607 | } 608 | 609 | video-encoding-offer = { 610 | 0: uint ; encoding-id 611 | 1: text ; codec-name 612 | 2: uint ; time-scale 613 | ? 3: uint ; default-duration 614 | ? 4: video-rotation ; default-rotation 615 | } 616 | 617 | data-encoding-offer = { 618 | 0: uint ; encoding-id 619 | 1: text ; data-type-name 620 | 2: uint ; time-scale 621 | ? 3: uint ; default-duration 622 | } 623 | 624 | audio-encoding-request = { 625 | 0: uint ; encoding-id 626 | } 627 | 628 | video-encoding-request = { 629 | 0: uint ; encoding-id 630 | ? 1: video-resolution ; target-resolution 631 | ? 2: ratio ; max-frames-per-second 632 | } 633 | 634 | data-encoding-request = { 635 | 0: uint ; encoding-id 636 | } 637 | 638 | video-rotation = &( 639 | ; Degrees clockwise 640 | video-rotation-0: 0 641 | video-rotation-90: 1 642 | video-rotation-180: 2 643 | video-rotation-270: 3 644 | ) 645 | 646 | sender-stats-audio = { 647 | 0: uint ; encoding-id 648 | ? 1: uint ; cumulative-sent-frames 649 | ? 2: microseconds ; cumulative-encode-delay 650 | } 651 | 652 | sender-stats-video = { 653 | 0: uint ; encoding-id 654 | ? 1: microseconds ; cumulative-sent-duration 655 | ? 2: microseconds ; cumulative-encode-delay 656 | ? 3: uint ; cumulative-dropped-frames 657 | } 658 | 659 | ; type key 131 660 | streaming-session-sender-stats-event = { 661 | 0: uint; streaming-session-id 662 | 1: microseconds ; system-time 663 | ? 2: [1* sender-stats-audio] ; audio 664 | ? 3: [1* sender-stats-video] ; video 665 | } 666 | 667 | streaming-buffer-status = &( 668 | enough-data: 0 669 | insufficient-data: 1 670 | too-much-data: 2 671 | ) 672 | 673 | receiver-stats-audio = { 674 | 0: uint ; encoding-id 675 | ? 1: microseconds ; cumulative-received-duration 676 | ? 2: microseconds ; cumulative-lost-duration 677 | ? 3: microseconds ; cumulative-buffer-delay 678 | ? 4: microseconds ; cumulative-decode-delay 679 | ? 5: streaming-buffer-status ; remote-buffer-status 680 | } 681 | 682 | receiver-stats-video = { 683 | 0: uint ; encoding-id 684 | ? 1: uint ; cumulative-decoded-frames 685 | ? 2: uint ; cumulative-lost-frames 686 | ? 3: microseconds ; cumulative-buffer-delay 687 | ? 4: microseconds ; cumulative-decode-delay 688 | ? 5: streaming-buffer-status ; remote-buffer-status 689 | } 690 | 691 | ; type key 132 692 | streaming-session-receiver-stats-event = { 693 | 0: uint; streaming-session-id 694 | 1: microseconds ; system-time 695 | ? 2: [1* receiver-stats-audio] ; audio 696 | ? 3: [1* receiver-stats-video] ; video 697 | } 698 | 699 | -------------------------------------------------------------------------------- /archive/control_protocol.md: -------------------------------------------------------------------------------- 1 | # Open Screen Control Protocol 2 | 3 | This document describes a control protocol suitable to support the 4 | implementation of 5 | the [Presentation API](https://w3c.github.io/presentation-api/) and 6 | the [Remote Playback API](https://w3c.github.io/remote-playback/). It is 7 | intended to be implemented on top of one of the proposed Open Screen transport 8 | mechanisms such as [QUIC](quic.md) or [RTCDataChannel](datachannel.md). 9 | 10 | The control protocol is responsible for mapping Web application requests and 11 | data provided by Web applications onto a network transport for transmission 12 | between controlling user agents and receivers (hosted on presentation displays 13 | and remote playback devices). 14 | 15 | This document focuses on the syntax and semantics of the network messages 16 | themselves. A future update will map these messages onto specific steps in the 17 | algorithms described in the respective specifications for the Presentation API 18 | and the Remote Playback API. 19 | 20 | ## Requirements 21 | 22 | * The control protocol must implement 23 | the [functional requirements for the Presentation API](requirements.md#presentation-api-requirements). 24 | * The control protocol must implement 25 | the [functional requirements for the Remote Playback API](requirements.md#remote-playback-api-requirements). 26 | * The control protocol must meet [non-functional requirements](requirements.md#non-functional-requirements). 27 | 28 | If an [RTCDataChannel](datachannel.md) is used as the transport, additional 29 | messages will be required to exchange WebRTC signaling messages to establish the 30 | channel. 31 | 32 | ## Message Transport 33 | 34 | To meet the requirements above, a message oriented control protocol is 35 | necessary. That means that each party should be able to transmit a sequence of 36 | variable-length messages from the other, and have every message received by the 37 | other party, intact and in-order. 38 | 39 | The RTCDataChannel supports variable length messages by virtue of 40 | adopting [SCTP](https://tools.ietf.org/html/rfc4960) as its message transmission 41 | protocol. The 42 | [RTCDataChannel specification](https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-13) 43 | suggests there may be 44 | [implementation restrictions on message size](https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-13#section-4) 45 | and that implementations should 46 | [interleave messages](https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-13#section-6.6) 47 | for fairness. 48 | 49 | Meanwhile, QUIC is stream-oriented and not message oriented, so a message 50 | oriented framing must be defined on top of it. In light of this, this control 51 | protocol defines its own message framing format. 52 | 53 | It is assumed that reliability, in-order delivery, and message integrity are 54 | ensured by the tranport and security layer, and they are not addressed here. 55 | (Note that each message does have a sequence ID that allows user agents 56 | to process messages in the order they were generated.) 57 | 58 | ## Message Format 59 | 60 | Messages are sent among parties responsible for implementing the Presentation 61 | API or the Remote Playback API. The message format should allow each party to 62 | deserialize each message as it arrives over the transport and dispatch it to 63 | appropriate code in the implementation of each API. 64 | 65 | ## Message Flavors 66 | 67 | Messages come in four flavors: Commands, Requests, Responses, and Events. 68 | 69 | - Commands are unidirectional messages sent from one party to a single 70 | recipient. No response is expected from the recipient. 71 | - Requests are sent from one party to a single recipient. That recipient must 72 | reply with a Response back to the initial sender that contains a reference to 73 | the sequence ID of the Request. 74 | - Events are sent from a single party to one or more recipients. No 75 | responses are expected from any recipient. 76 | 77 | ### Message Structure 78 | 79 | Messages are structured as a 36 byte message header, followed by a variable 80 | length message body. 81 | 82 | ``` 83 | Byte offset 84 | 0 +-------------------+ 85 | + PROTOCOL_ID + 86 | 4 +-------------------+ 87 | + FLAGS + 88 | 8 +-------------------+ 89 | + MESSAGE_LENGTH + 90 | 16 +-------------------+ 91 | + MESSAGE_TYPE + 92 | 24 +-------------------+ 93 | + SEQUENCE_ID + 94 | 32 +-------------------+ 95 | + REQUEST_ID + 96 | 36 +-------------------+ 97 | + MESSAGE BODY + 98 | . . 99 | . . 100 | . . 101 | +-------------------+ 102 | ``` 103 | 104 | 105 | The overall length of a message is constrained only by the `MESSAGE_LENGTH` 106 | field, or 2^64 - 1 bytes. Practically speaking, messages are limited by the 107 | memory capacity of each party, the underlying tansport, and the necessity of 108 | transmitting messages in a reasonable amount of time. 109 | 110 | All integers are to be represented in [network byte order](https://tools.ietf.org/html/rfc1700). 111 | 112 | 113 | - `PROTOCOL_ID`: A 32-bit value explained below. 114 | - `FLAGS`: A 32-bit value explained below. 115 | - `MESSAGE_LENGTH`: A 64-bit unsigned integer that contains the number of bytes 116 | in the entire message (including all header fields). 117 | - `MESSAGE_TYPE`: A 64-bit value that identifies the message content. 118 | - `SEQUENCE_ID`: A 64-bit, positive unsigned integer that is used to uniquely 119 | identify messages originating from one party, and to ensure that messages are 120 | handled in the proper order by the recipient. 121 | - `REQUEST_ID`: An optional 64-bit unsigned integer. If the message flavor is a 122 | Response, it contains the `SEQUENCE_ID` of the Request that the response is 123 | replying to. For other flavors, it is not present. 124 | 125 | The content of the `MESSAGE_BODY` is not constrained by the generic message 126 | structure, and must be interpreted according to the `MESSAGE_TYPE`. 127 | 128 | **TODO:** Investigate variable length integers for `MESSAGE_LENGTH`, 129 | `SEQUENCE_ID` to save bytes for short messages. See 130 | [Issue #45](https://github.com/webscreens/openscreenprotocol/issues/45). 131 | 132 | ### Protocol ID 133 | 134 | The `PROTOCOL_ID` informs the recipient how to process the following 135 | message, including the remaining headers. 136 | 137 | ``` 138 | Bit offset 139 | 0 +---------------------------+ 140 | + PROTOCOL_TYPE + 141 | 16 +---------------------------+ 142 | + VERSION_MAJOR + 143 | 24 +---------------------------+ 144 | + VERSION_MINOR + 145 | 32 +---------------------------+ 146 | ``` 147 | 148 | `PROTOCOL_TYPE` is a 16-bit unsigned integer that identifies the specific API, 149 | protocol, or feature that will generate and consume this message. 150 | Protocol type 0 is not valid, and types 1-32,767 will be reserved for publicly 151 | defined control protocols. We assign the following two types: 152 | 153 | - 1 for Presentation API Control Protocol 154 | - 2 for Remote Playback API Control Protocol 155 | 156 | Types 32,768 - 65,535 are reserved for private or vendor-specific control 157 | protocols. 158 | 159 | `VERSION_MAJOR` and `VERSION_MINOR` identify the version of the control protocol 160 | in use. It's expected, but not required, that the same version will be used 161 | throughout the lifetime of a connection between two user agents. The `MAJOR` 162 | and `MINOR` fields are 8-bit unsigned integers that specify a conventional 163 | major.minor version number. The smallest legal version number is 0.1. 164 | 165 | ### Version Numbers and Cross-Version Compatibility 166 | 167 | Minor versions denote minor changes to an existing control protocol, that would 168 | require minimal or no code changes by the controlling user agent or receiver. 169 | It's expected that a controlling user agent using version X.Z would be able to 170 | interoperate with a receiver supporting version X.Y, for any value of Z and Y. 171 | 172 | Major versions indicate significant (and possibly backwards/forwards 173 | incompatible) changes to a control protocol. Controllers should support as many 174 | major versions of a control protocol as there are receivers "in the field." 175 | 176 | Through discovery, the controlling user agent should obtain the the maxmimum 177 | protocol version supported by the receiver that is also supported by the 178 | controlling user agent. That version of the protocol should be used by the 179 | controlling user agent going forward. 180 | 181 | **TODO:** Update discovery proposals with means for controlling user agents to 182 | discover supported protocols & versions. 183 | 184 | ### Flags 185 | 186 | The `FLAGS` value is a 32-bit array of flags, each carrying a true/set or 187 | false/unset value. The table below lists the meaning of each position. 188 | 189 | Position | Meaning when set | Meaning when not set 190 | ---------|-------------------|--------------------- 191 | 0 | Sequence ID reset | Ignored 192 | 1-31 | Reserved | Reserved 193 | 194 | ### Sequence IDs 195 | 196 | Sequence IDs begin at 1 and are incremented by 1 each time a message is 197 | generated by a controlling user agent or receiver. IDs originating from the 198 | same source must not be duplicated. Typically, IDs originating from the same 199 | source will be contiguous, but this is not required; only that they are 200 | monotonically increasing. 201 | 202 | If the sequence ID reaches `2^64 - 1`, it will wrap around to 1 for the next 203 | message, and that message will have its flag 0 set. 204 | 205 | ### Message Types 206 | 207 | The `MESSAGE_TYPE` field is as follows: 208 | 209 | ``` 210 | Bit offset 211 | 0 +---------------------------+ 212 | + MESSAGE_FLAVOR + 213 | 8 +---------------------------+ 214 | + MESSAGE_TYPE_ID + 215 | 24 +---------------------------+ 216 | + MESSAGE_SUBTYPE_ID + 217 | 40 +---------------------------+ 218 | + RESERVED + 219 | 64 +---------------------------+ 220 | ``` 221 | 222 | `MESSAGE_FLAVOR` is an 8-bit unsigned integer that conveys the message flavor: 223 | 224 | Value | Flavor 225 | ------|------- 226 | 0 | Command 227 | 1 | Request 228 | 2 | Response 229 | 3 | Event 230 | 231 | `MESSAGE_TYPE_ID` and `MESSAGE_SUBTYPE_ID` are protocol-specific. The 232 | `MESSAGE_TYPE_ID` is used to group related messages together, and 233 | `MESSAGE_SUBTYPE_ID` can distinguish individual message types within that group. 234 | 235 | **TODO**: Define an extensions format to allow additional data to be bundled 236 | with a defined message type. 237 | 238 | ## Presentation API Control Protocol 239 | 240 | To outline the control protocol, we describe the messages used to implement each 241 | of the 242 | [Presentation API requirements](requirements.md#presentation-api-requirements). 243 | For brevity, each message is described by its flavor, its type, its subtype, and 244 | the structure of the message body. 245 | 246 | ### Message types 247 | 248 | The Presentation API control protocol uses five message types according to the 249 | functionality implemented by the message. 250 | 251 | Message Type (hex) | Functionality 252 | -------------------|--------------- 253 | 0x0001 | Presentation Display Availability 254 | 0x0002 | Presentation Lifecycle 255 | 0x0003 | Presentation Connection Management 256 | 0x0004 | Presentation Application Messages 257 | 0x0005 | Receiver Status 258 | 259 | ### Presentation Display Availability 260 | 261 | To meet the [Presentation Display 262 | Availability](requirements.md#presentation-display-availability) requirement, 263 | the controlling user agent shall generate a Presentation Display Availaiblity 264 | Request and the receiver shall respond with a Presentation Display Availability 265 | Response. 266 | 267 | #### Presentation Display Availablity Request 268 | 269 | This message is sent by a controlling user agent to find whether a receiver is 270 | compatible with potential presentation URLs. The request may be sent when a 271 | controlling user agent is [monitoring the list of available presentation 272 | displays](https://w3c.github.io/presentation-api/#dfn-monitor-the-list-of-available-presentation-displays) 273 | (when starting a presentation or monitoring availability in the background), or 274 | when a new presentation display is discovered. 275 | 276 | ``` 277 | Flavor: Request 278 | Type: 0x0001 279 | Subtype: 0x0001 280 | 281 | Byte Offset 282 | 32 +-----------------------+ 283 | + NUM_URLS + 284 | 34 +-----------------------+ 285 | + URL_1_LENGTH + 286 | 38 +-----------------------+ 287 | + URL_1_CONTENT + 288 | +-----------------------+ 289 | + URL_2_LENGTH + 290 | +-----------------------+ 291 | + URL_2_CONTENT + 292 | +-----------------------+ 293 | . . 294 | +-----------------------+ 295 | + URL_N_LENGTH + 296 | +-----------------------+ 297 | + URL_N_CONTENT + 298 | +-----------------------+ 299 | ``` 300 | 301 | 302 | - `NUM_URLS` is an unsigned positive 16-bit integer with the number of URLs 303 | contained in the message. 304 | - `URL_N_LENGTH` is an unsigned 32-bit integer with the length, in bytes, of the 305 | Nth URL. 306 | - `URL_N_CONTENT` is the Nth URL contained in the message, encoded according to 307 | [RFC 3986](https://tools.ietf.org/html/rfc3986#section-2). 308 | 309 | Note that this request will send presentation URLs from controlling user agents 310 | to receivers, even before the user has selected the corresponding display for 311 | presentation. An alternative mechanism would allow the controlling user agent 312 | to retrieve URL patterns from a receiver that match the URLs supported by that 313 | receiver. 314 | 315 | **TODO**: Add messages for this based on conclusion to 316 | [Issue #21](https://github.com/webscreens/openscreenprotocol/issues/21). 317 | 318 | Note that the URLs sent by the Presentation Availability Request may contain 319 | custom (non-https) schemes. Please review [Schemes and Open Screen 320 | Protocol](schemes.md) for how custom schemes are handled in OSP. 321 | 322 | #### Presentation Display Availablity Response 323 | 324 | The receiver shall send a response for each Presentation Display Availability 325 | Request as follows. The receiver may use the order it returns its availability 326 | results to indicate its preference for which URL should be presented on that 327 | display. 328 | 329 | ``` 330 | Flavor: Response 331 | Type: 0x0001 332 | Subtype: 0x0002 333 | 334 | Byte Offset 335 | 40 +-----------------------+ 336 | + NUM_URLS + 337 | 42 +-----------------------+ 338 | + INDEX_1 + 339 | 44 +-----------------------+ 340 | + AVAILABILITY_RESULT_1 + 341 | 45 +-----------------------+ 342 | . . 343 | +-----------------------+ 344 | + INDEX_N + 345 | +-----------------------+ 346 | + AVAILABILITY_RESULT_N + 347 | +-----------------------+ 348 | ``` 349 | 350 | - `NUM_URLS` is an unsigned positive 16-bit integer that is identical to 351 | `NUM_URLS` in the corresponding Presentation Display Availability Request. 352 | - Each `INDEX_N` is an unsigned 16-bit integer corresponding to the index 353 | position of the Nth URL in the Presentation Availability Request (starting 354 | from zero). 355 | - Each `AVAILABILITY_RESULT_N` is an unsigned 8-bit integer containing the 356 | availability result for the `INDEX_N`th URL in the request. The results are 357 | as follows: 358 | 359 | Availability Result | Meaning 360 | --------------------|-------- 361 | 0 | The URL is not compatible with the receiver. 362 | 1 | The URL is compatible with the receiver. 363 | 10 | The URL was not valid URL. 364 | 100 | The availability check timed out. 365 | 101 | The availability check failed (transient error). 366 | 102 | The availability check failed (permanent error). 367 | 199 | Unknown or other error processing URL. 368 | 369 | 370 | ### Presentation Lifecycle 371 | 372 | #### Presentation Initiation Request 373 | 374 | This message is sent by a controlling user agent to start presentation on a 375 | receiver. The URL must be one that has been previously reported as compatible 376 | by that display. 377 | 378 | ``` 379 | Flavor: Request 380 | Type: 0x0002 381 | Subtype: 0x0001 382 | 383 | Byte Offset 384 | 32 +-----------------------+ 385 | + PRESENTATION_ID + 386 | 160 +-----------------------+ 387 | + HEADERS_LENGTH + 388 | 162 +-----------------------+ 389 | + HEADERS_CONTENT + 390 | +-----------------------+ 391 | + URL_LENGTH + 392 | +-----------------------+ 393 | + URL_CONTENT + 394 | +-----------------------+ 395 | ``` 396 | 397 | - `PRESENTATION_ID` is a null (zero-byte) terminated ASCII string of 128 bytes 398 | that communicates the ID for the presentation. Values shorter than 128 bytes 399 | should be zero-byte padded. 400 | - `HEADERS_LENGTH` is a unsigned positive 16-bit integer with the length, in 401 | bytes, of the headers to include with the request to fetch the presentation 402 | URL. 403 | - `HEADERS_CONTENT` is the content of HTTP headers to include in the request to 404 | fetch the presentation URL. This field must be exactly `HEADERS_LENGTH` bytes 405 | in length and should follow the syntax of 406 | [RFC 7230](https://tools.ietf.org/html/rfc7230#section-3.2). 407 | - The `HEADERS_CONTENT` field must include an `Accept-Language` header as 408 | defined in [RFC 7231](https://tools.ietf.org/html/rfc7231#section-5.3.5) that 409 | communicates the preferred locale for the presentation. 410 | - `URL_LENGTH` is an unsigned positive 32-bit integer with the length, in bytes, 411 | of the presentation URL. 412 | - `URL_CONTENT` is the presentation URL, encoded according to RFC 3986. This 413 | field must be exactly `URL_LENGTH` bytes in length. 414 | 415 | Note that the URL sent in the Presentation Initiation Request may contain a 416 | custom (non-https) scheme. Please review [Schemes and Open Screen 417 | Protocol](schemes.md) for how custom schemes are handled in OSP. 418 | 419 | #### Presentation Initiation Response 420 | 421 | This message is sent by the receiver in reponse to a Presentation 422 | Initiation Request. It should be sent when either the receiver is ready to 423 | receive connections to the presentation, or presentation initiation encounters 424 | an error that prevents intiation from proceeding. 425 | 426 | ``` 427 | Flavor: Response 428 | Type: 0x0002 429 | Subtype: 0x0002 430 | 431 | Byte Offset 432 | 40 +-----------------------+ 433 | + PRESENTATION_ID + 434 | 168 +-----------------------+ 435 | + INITIATION_RESULT + 436 | 169 +-----------------------+ 437 | + HTTP_RESPONSE_CODE + 438 | 173 +-----------------------+ 439 | ``` 440 | 441 | - `PRESENTATION_ID` is a null (zero-byte) terminated ASCII string of exactly 128 442 | bytes that matches the Presentation ID sent in the Request. Values shorter 443 | than 128 bytes should be zero-byte padded. 444 | - `INITIATION_RESULT` is a one-byte result code as follows: 445 | 446 | Availability Result | Meaning 447 | --------------------|-------- 448 | 1 | The presentation was loaded successfully. 449 | 10 | The URL in the request was not valid URL. 450 | 100 | The initation request timed out. 451 | 101 | The initiation request failed (transient, non-HTTP error). 452 | 102 | The initiation request failed (permanent, non-HTTP error). 453 | 103 | The URL encountered an HTTP error while loading. 454 | 199 | Unknown or other error processing initiation request. 455 | 456 | - The `HTTP_RESPONSE_CODE` contains an unsigned 32-bit integer with the numeric 457 | HTTP response code resulting from loading the presentation URL for the 458 | request. 459 | 460 | #### Presentation Termination Request 461 | 462 | This message is sent by a controlling user agent to terminate a presentation. 463 | In general, the simplest and most usable approach is to allow any connected 464 | controlling user agent to terminate a presentation if they know its ID and URL. 465 | There is no response to this request, instead the controlling user agent should 466 | wait to receive the Presentation Termination Event to determine whether it was 467 | successful. 468 | 469 | **TODO**: If we need to return errors, then consider defining a Response. 470 | 471 | ``` 472 | Flavor: Command 473 | Type: 0x0002 474 | Subtype: 0x0003 475 | 476 | Byte Offset 477 | 32 +-----------------------+ 478 | + PRESENTATION_ID + 479 | 40 +-----------------------+ 480 | + URL_LENGTH + 481 | +-----------------------+ 482 | + URL_CONTENT + 483 | +-----------------------+ 484 | + TERMINATION_SOURCE + 485 | +-----------------------+ 486 | ``` 487 | 488 | - `PRESENTATION_ID` is a null (zero-byte) terminated ASCII string of 128 bytes 489 | that communicates the ID for the presentation. Values shorter than 128 bytes 490 | should be zero-byte padded. 491 | - `URL_LENGTH` is an unsigned positive 32-bit integer with the length, in bytes, 492 | of the presentation URL. 493 | - `URL_CONTENT` is the presentation URL, encoded according to RFC 3986. This 494 | field must be exactly `URL_LENGTH` bytes in length. 495 | - `TERMINATION_SOURCE` is a one-byte code describing the source of the 496 | termination request. 497 | 498 | Termination Source | Meaning 499 | -------------------|-------- 500 | 10 | A connected controller called `terminate()` on the connection object. 501 | 11 | A user terminated the presentation via the controlling user agent. 502 | 503 | Note that these codes must match up with reason codes in the Presenation 504 | Termination Event for terminations that come from a controlling user agent. 505 | 506 | #### Presentation Termination Event 507 | 508 | This event is sent by the receiver to all connected controlling user agents to 509 | inform them that a presentation has been terminated. 510 | 511 | ``` 512 | Flavor: Event 513 | Type: 0x0002 514 | Subtype: 0x0004 515 | 516 | Byte Offset 517 | 40 +-----------------------+ 518 | + PRESENTATION_ID + 519 | 168 +-----------------------+ 520 | + TERMINATION_REASON + 521 | ------------------------+ 522 | ``` 523 | 524 | - `PRESENTATION_ID` is a null (zero-byte) terminated ASCII string of exactly 128 525 | bytes that communicates the ID for the presentation that was terminated. 526 | Values shorter than 128 bytes should be zero-byte padded. 527 | - `TERMINATION_REASON` is a one-byte reason code as follows: 528 | 529 | Termination Reason | Meaning 530 | -------------------|-------- 531 | 1 | The presentation called connection.terminate(). 532 | 2 | A user terminated the presentation via the receiver or presentation display. 533 | 10 | A connected controller called connection.terminate(). 534 | 11 | A user terminated the presentation via the controlling user agent. 535 | 20 | A new presentation was started and replaced the current presentation. 536 | 30 | The presentation was terminated because it was idle for too long. 537 | 31 | The presentation was terminated because it attempted to navigate. 538 | 100 | The presentation display is powering down or the receiver is shutting down. 539 | 101 | The receiver had a fatal software error (i.e. crash). 540 | 255 | Unknown or other reason. 541 | 542 | ### Presentation Connection Management 543 | 544 | #### Presentation Connection Request 545 | 546 | This message is sent by a controlling user agent to a reciever to connect a 547 | controller to a presentation. The Presentation URL and Presentation ID should 548 | correspond to a presentation that has been started on the receiver through a 549 | successful Presentation Initiation Request. 550 | 551 | ``` 552 | Flavor: Request 553 | Type: 0x0003 554 | Subtype: 0x0001 555 | 556 | Byte Offset 557 | 32 +-----------------------+ 558 | + PRESENTATION_ID + 559 | 160 +-----------------------+ 560 | + URL_LENGTH + 561 | 164 +-----------------------+ 562 | + URL_CONTENT + 563 | +-----------------------+ 564 | ``` 565 | 566 | - `PRESENTATION_ID` is a null (zero-byte) terminated ASCII string of exactly 128 567 | bytes that communicates the ID for the presentation. Values shorter than 128 568 | bytes should be zero-byte padded. 569 | - `URL_LENGTH` is an unsigned positive 32-bit integer with the length, in bytes, 570 | of the presentation URL that was sent in the corresponding Presentation 571 | Initiation Request. 572 | - `URL_CONTENT` is the presentation URL, encoded according to RFC 3986. This 573 | field must be exactly `URL_LENGTH` bytes in length. 574 | 575 | ### Presentation Connection Response 576 | 577 | This message is sent by the receiver to the controlling user agent in reponse to 578 | a Presentation Connection Request. One should be sent for every Presentation 579 | Connection Request regardless of whether it was successful or not. 580 | 581 | ``` 582 | Flavor: Response 583 | Type: 0x0003 584 | Subtype: 0x0002 585 | 586 | Byte Offset 587 | 40 +-----------------------+ 588 | + PRESENTATION_ID + 589 | 42 +-----------------------+ 590 | + CONNECTION_ID + 591 | 46 +-----------------------+ 592 | + CONNECTION_RESULT + 593 | 47 +-----------------------+ 594 | ``` 595 | 596 | - `PRESENTATION_ID` is a null (zero-byte) terminated ASCII string of exactly 128 597 | bytes that communicates the ID for the presentation. Values shorter than 128 598 | bytes should be zero-byte padded. 599 | - `CONNECTION_ID` is a 32-bit positive integer that starts at 1 and is 600 | incremented by one for each successful connection to the presentation page. 601 | If there was an error connecting to the page, it is zero. 602 | - `CONNECTION_RESULT` is a one-byte result code as follows: 603 | 604 | Connection Result | Meaning 605 | --------------------|-------- 606 | 1 | A connection was created successfully. 607 | 10 | The URL in the request was not valid URL. 608 | 11 | The ID in the request was not a valid ID. 609 | 12 | The URL and ID do not match any known presentation. 610 | 100 | The connection request timed out. 611 | 101 | The connection request could not be handled at this time (transient). 612 | 102 | The connection request was refused (permanent). 613 | 103 | The presentation is in the process of terminating and cannot accept new connections. 614 | 199 | Unknown or other error processing connection request. 615 | 616 | #### Presentation Connection Close Event 617 | 618 | This message is sent by either the receiver or the controlling user agent to the 619 | other party to notify that a presentation connection has been closed. Note that 620 | there is no specific response to this event, as it's main purpose is to fire a 621 | correct `PresentationConnectionCloseEvent` on the other party's connection 622 | object. 623 | 624 | ``` 625 | Flavor: Event 626 | Type: 0x0003 627 | Subtype: 0x0003 628 | 629 | Byte Offset 630 | 40 +-----------------------+ 631 | + PRESENTATION_ID + 632 | 42 +-----------------------+ 633 | + CONNECTION_ID + 634 | 46 +-----------------------+ 635 | + CLOSE_REASON + 636 | 47 +-----------------------+ 637 | + ERROR_MESSAGE + 638 | 559 +-----------------------+ 639 | ``` 640 | 641 | - `PRESENTATION_ID` is a null (zero-byte) terminated ASCII string of exactly 128 642 | bytes that communicates the ID for the presentation. Values shorter than 128 643 | bytes should be zero-byte padded. 644 | - `CONNECTION_ID` is a 32-bit positive integer that corresponds to a connection 645 | to between the controller and receiver. 646 | - `CLOSE_REASON` is a one-byte reason code as follows: 647 | 648 | Close Reason | Meaning 649 | ---------------|-------- 650 | 1 | The controller or presentation called `close()` on the connection object. 651 | 10 | The controller or presentation discarded the connection object or navigated away. 652 | 100 | The connection encountered an unrecoverable error while sending or receiving a message. 653 | 654 | - `ERROR_MESSAGE` is an optional, null (zero-byte) terminated ASCII string of 655 | exactly 512 bytes describing the error that occurred handling a message. 656 | If it is less than 512 bytes, it should be zero padded. If there is no 657 | message, it should be all zeros. 658 | 659 | It's not expected that either party send a Close Event when encountering a 660 | network or tranport level error, as an invalid transport would prevent the 661 | reliable delivery of the command anyway. Instead the user agent should fire the 662 | `PresentationConnectionClose` event locally on connection objects based on its 663 | observation of the network state. 664 | 665 | **NOTE:** If the control channel and individual presentation connections use 666 | different network connections or transports, it would make sense to enumerate 667 | specific network errors here for the network failure of an individual 668 | presentation connection. 669 | 670 | ### Presentation Application Message 671 | 672 | This message is used to transmit an application message between the controller 673 | and presentation, via the `send()` method on the connection object. 674 | 675 | ``` 676 | Flavor: Command 677 | Type: 0x0004 678 | Subtype: 0x0001 679 | 680 | Byte Offset 681 | 32 +-----------------------+ 682 | + PRESENTATION_ID + 683 | 160 +-----------------------+ 684 | + CONNECTION_ID + 685 | 164 +-----------------------+ 686 | + MESSAGE_TYPE + 687 | 165 +-----------------------+ 688 | + MESSAGE_LENGTH + 689 | 197 +-----------------------+ 690 | + MESSAGE_CONTENT + 691 | +-----------------------+ 692 | ``` 693 | 694 | - `PRESENTATION_ID` is a null (zero-byte) terminated ASCII string of 128 bytes 695 | that communicates the ID for the presentation. Values shorter than 128 bytes 696 | should be zero-byte padded. 697 | - `CONNECTION_ID` is a 32-bit positive integer that corresponds to the ID of the 698 | receiver `PresentationConnection` that is conveying the message. 699 | - `MESSAGE_TYPE` is a one-byte code describing the message type as follows: 700 | 701 | Message Type | Meaning 702 | -------------|-------- 703 | 1 | Text message 704 | 2 | Binary message 705 | 3 | Empty text message 706 | 707 | - `MESSAGE_LENGTH` is an unsigned 32-bit integer with the length, in bytes, 708 | of the message content. 709 | - `MESSAGE_CONTENT` is the content of the message. It must be exactly 710 | `MESSAGE_LENGTH` bytes in length. For text messages, the `MESSAGE_CONTENT` 711 | must correspond to a valid and non-empty UTF-8 string. For binary messages, 712 | the content is arbitrary binary data. 713 | 714 | A `MESSAGE_TYPE` of 3 corresponds to an empty string, i.e. `send('')`. 715 | If the `MESSAGE_TYPE` is 3, the `MESSAGE_LENGTH` must be zero. 716 | 717 | **TODO:** Do we need special handling of empty binary messages, i.e. `new 718 | ArrayBuffer(0)` 719 | 720 | ### Presentation Receiver Status Event 721 | 722 | This message allows the receiver to broadcast status information to all 723 | connected controlling user agents. It may be sent at any time, but should be 724 | sent when the content of a Display Info or Presentation Info has changed since 725 | the last broadcast. The receiver may be configured to broadcast a subset of the 726 | information in this message or none at all depending on the policies and privacy 727 | preferences of the user. 728 | 729 | This Receiver Status event is a composition of sub-messages. See below for the 730 | breakout of the sub-message formats. 731 | 732 | ``` 733 | Flavor: Event 734 | Type: 0x0005 735 | Subtype: 0x0001 736 | 737 | Byte Offset 738 | 32 +-----------------------+ 739 | + DISPLAY_INFO + 740 | K +-----------------------+ 741 | + NUM_PRESENTATION_INFO + 742 | K+4 +-----------------------+ 743 | + PRESENTATION_INFO_1 + 744 | +-----------------------+ 745 | + ... + 746 | +-----------------------+ 747 | + PRESENTATION_INFO_N + 748 | +-----------------------+ 749 | ``` 750 | 751 | ### Display Info 752 | 753 | The Display Info struct conveys information about the presentation display 754 | device itself. Currently this includes information about the friendly name 755 | which may be too long to fit in a discovery protocol message. 756 | 757 | ``` 758 | Byte Offset 759 | 0 +-----------------------+ 760 | + FRIENDLY_NAME_LOCALE + 761 | 64 +-----------------------+ 762 | + FRIENDLY_NAME_LENGTH + 763 | 66 +-----------------------+ 764 | + FRIENDLY_NAME_CONTENT + 765 | +-----------------------+ 766 | ``` 767 | 768 | - `FRIENDLY_NAME_LOCALE` is a 64-byte, zero terminated ASCII value with the 769 | BCP-47 language code of the friendly name. If it is shorter than 64 bytes, it 770 | should be right-padded by zeroes. 771 | - `FRIENDLY_NAME_LENGTH` is a 2-byte positive unsigned integer with the length 772 | of `FRIENDLY_NAME_CONTENT`. 773 | - `FRIENDLY_NAME_CONTENT` is a valid UTF-8 encoded string with the friendly name 774 | of the presentation display. It is exactly `FRIENDLY_NAME_LENGTH` bytes in 775 | length. 776 | 777 | **TODO:** 778 | [Representation of BCP-47 language tags](https://github.com/webscreens/openscreenprotocol/issues/47) 779 | 780 | ### Presentation Info 781 | 782 | The Presentation Info struct conveys information about a running presentation. 783 | All fields are optional. By advertising a presentation's URL and ID, the 784 | receiver will allow any connected controlling user agent to connect to that 785 | presentation. 786 | 787 | ``` 788 | Byte Offset 789 | 0 +-----------------------+ 790 | + PRESENTATION_ID + 791 | 128 +-----------------------+ 792 | + URL_LENGTH + 793 | 132 +-----------------------+ 794 | + URL_CONTENT + 795 | K +-----------------------+ 796 | + NUM_CONNECTIONS + 797 | K+2 +-----------------------+ 798 | + TITLE_LOCALE + 799 | K+66 +-----------------------+ 800 | + TITLE_LENGTH + 801 | K+78 +-----------------------+ 802 | + TITLE_CONTENT + 803 | +-----------------------+ 804 | ``` 805 | 806 | - `PRESENTATION_ID` is a null (zero-byte) terminated ASCII string of 128 bytes 807 | that communicates the ID for the presentation. Values shorter than 128 bytes 808 | should be zero-byte padded. If omitted, it should be all zeros. 809 | - `URL_LENGTH` is an unsigned positive 32-bit integer with the length, in bytes, 810 | of the presentation URL. The presentation URL is omitted, it should be zero. 811 | - `URL_CONTENT` is the presentation URL, encoded according to RFC 3986. This 812 | field must be exactly `URL_LENGTH` bytes in length. If the presentation URL 813 | is omitted, this field is not present. 814 | - `NUM_CONNECTIONS` is an unsigned 2-byte integer that holds the number of 815 | presentation connections that are in a `connected` state. If omitted, this 816 | field is zero. 817 | - `TITLE_LOCALE` is is a 64-byte, zero terminated ASCII value with the BCP-47 818 | language code of the friendly name. If it is shorter than 64 bytes, it should 819 | be right-padded by zeroes. If the presentation title omitted, it is all 820 | zeros. 821 | - `TITLE_LENGTH` is a 2-byte positive unsigned integer with the length 822 | of `TITLE_CONTENT`. If the presentation title is omitted, this is zero. 823 | - `TITLE_CONTENT` is a valid UTF-8 encoded string with the [title of the 824 | presentation document](https://html.spec.whatwg.org/multipage/semantics.html#the-title-element). 825 | It is exactly `TITLE_LENGTH` bytes in length. If the presentation title is 826 | omitted, this field is not present. 827 | 828 | **NOTE**: We could add a status flag to tell controlling user agents the status 829 | of the presentation (loading/ready/terminating/terminated). 830 | 831 | **NOTE:** We could allow the receiver to broadcast only the origin of the 832 | presentation, not the full URL, for display purposes in the controlling user 833 | agent. In that case, we would need to add a flag to convey this so the 834 | controller knows not to attempt reconnection with just the origin. 835 | 836 | ## Remote Playback API Control Protocol 837 | 838 | **TODO:** Fill in when Remote Playback requirements are known. See 839 | [Issue #3](https://github.com/webscreens/openscreenprotocol/issues/3). 840 | 841 | ## Design Discussion 842 | 843 | ### JSON 844 | 845 | [JSON](http://www.json.org/) is an alternative format that could be used as a 846 | syntax for the control protocol. It is Web friendly and human 847 | readable. However: 848 | 849 | - JSON is less efficient for translating a given set of structured data to the 850 | wire, especially binary data. 851 | - JSON generation and parsing requires a larger code footprint. 852 | - JSON parsing is a potential source of security vulnerabilities. 853 | - JSON is a very generic and untyped syntax; a full protocol specification would 854 | need to clearly define how to handle missing fields, non-conformant types, 855 | extraneous fields, quoting, and a myriad of other corner cases. Correct 856 | implementations would then need to write validation code for the same. 857 | 858 | For these reasons, this proposal does not purse JSON as a control protocol 859 | format. It should be straightforward to write code that translates binary 860 | protocol messages into human readable strings for logging and debugging. 861 | 862 | ### Message Routing 863 | 864 | It may be desirable to add additional routing data to the basic message 865 | structure. It's reasonable to assume that messages between controllers and 866 | presentations are handled by the same code paths in controlling user agents and 867 | receivers. This routing information would be used to ensure that the messages 868 | are sent between the correct processes (in a multi-process browser) and 869 | ultimately to the correct browsing contexts to activate the corresponding Web 870 | APIs. 871 | 872 | Routing data could take the form of a source and/or target ids, which would be 873 | assigned by user agents and mapped to individual browsing contexts within that 874 | user agent. 875 | 876 | If a separate transport (or transport stream) is always used to connect one 877 | browsing context with another, then there may be no need for additional routing 878 | at the message protocol layer. QUIC supports the layering of streams over a 879 | single device-to-device transport, while RTCDataChannel does not. If we don't 880 | include routing data, a separate RTCDataChannel would be required for each 881 | frame-to-frame connection. 882 | 883 | ### Role Reversal 884 | 885 | The underlying control protocol should be symmetric; meaning, that either end of 886 | the network transport can take the role of the controlling user agent or 887 | receiver (regardless of who discovered whom). This could enable scenarios 888 | whereby an application loaded on a presentation display initiates presentation 889 | on a mobile or laptop device whose user agent implements the receiver role of 890 | the protocol (responding to availability and presentation requests, etc.) 891 | 892 | To fully realize this, the protocol needs to be extended with a capabilities 893 | exchange so that each party knows what roles the other may assume (controlling 894 | user agent, receiver, or both). 895 | 896 | **TODO**: Add protocol support for capability/role advertisement. 897 | 898 | ### Language Tags 899 | 900 | 901 | -------------------------------------------------------------------------------- /archive/datachannel.md: -------------------------------------------------------------------------------- 1 | # Data Channel 2 | 3 | [Data Channel](https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-13) is 4 | a non-media transport protocol in the WebRTC framework, designed for exchanging 5 | data from peer to peer. It advertises the following benefits: 6 | 7 | - Implemented in major browsers. 8 | - Supports heterogeneous network environments, e.g., NAT, firewall. 9 | - Easily supports media transport for remote playback. 10 | - Data framing format is already defined. 11 | 12 | # Design and Specification 13 | 14 | - [WebRTC overview](https://tools.ietf.org/html/draft-ietf-rtcweb-overview-18) 15 | - IETF draft: [WebRTC Data Channel Establishment Protocol](https://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-09) 16 | - IETF draft: [Data Channel](https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-13) 17 | 18 | # Presentation API functionality 19 | 20 | Data Channel is designed to be a non-media transport for WebRTC, with a built-in 21 | sub protocol negotiation mechanism. 22 | 23 | A Data Channel is built on top of a 24 | [SCTP](https://tools.ietf.org/html/rfc4960)/[DTLS](https://tools.ietf.org/html/rfc6347)/UDP 25 | protocol stack, which supports reliable data transmission. Each Data Channel has 26 | a unique integer ID and a label. Mutiple Data Channels can share the same DTLS 27 | connection. 28 | 29 | Assume that a single Data Channel is used as a control channel to transmit 30 | control messages between the controlling user agent and receiver, and one Data 31 | Channel is created for each presentation connection to exchange application 32 | data. 33 | 34 | An extra signalling channel and protocol for exchanging ICE candidates is 35 | required to bootstrap the control channel. The bootstrapping procedure needs to 36 | be executed before Presentation Initiation, Presentation Resumption, or 37 | Presentation Connection Establishment. 38 | 39 | ## Presentation Initiation 40 | 41 | 1. To start a presentation, the controlling user agent sends a message to the 42 | receiver on the control channel with the presentation ID and URL of the 43 | initial presentation connection. 44 | 2. The receiver spawns a Data Channel on the same RTC connection as the control 45 | channel, with a unique session ID generated as the label. 46 | 3. The controlling user agent gets a reply on the control channel with the 47 | presentation ID, URL, and session ID to confirm success (or report an error). 48 | 49 | ## Presentation Resumption 50 | 51 | 1. To reconnect to a presentation, the controlling user agent sends a message to 52 | the receiver on the control channel with the presentation ID, URL, and 53 | session ID of the initial presentation connection. 54 | 2. If there is a corresponding presentation to be resumed, the receiver spawns a 55 | Data Channel on the same RTC connection as the control channel, with the 56 | session ID as the label. 57 | 3. The controlling user agent gets a reply on control channel with the 58 | presentation ID, URL, and session ID to confirm success (or report an error). 59 | 60 | ## Presentation Connection Establishment 61 | 62 | Multiple connections from a controlling user agent can be handled by creating 63 | unique Data Channels for each peer. A unique stream ID will be selected for 64 | muxing/demuxing messages on the underlying SCTP transport, see 65 | [draft-ietf-rtcweb-data-protocol-09](https://tools.ietf.org/html/draft-ietf-rtcweb-data-protocol-09#section-6). 66 | 67 | ## Presentation Connection Messaging 68 | 69 | Binary or text messages can be sent on the Data Channel corresponding to the 70 | presentation connection. The framing of these messages is defined in 71 | [draft-ietf-rtcweb-data-channel](https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-13#section-6.6). 72 | 73 | Either side may close the Presentation Connection through the following procedure: 74 | 1. Send a control message with close reason on control channel to remote peer. 75 | 2. When the remote peer receives the control message, it initiates the 76 | [Data Channel close procedure](https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-13#section-6.6). 77 | 3. Close the presentation connection when the underlying Data Channel is closed. 78 | 79 | ## Presentation Termination 80 | 81 | For controlling user agent initiated termination: 82 | 1. The controlling user agent sends a control message with the presentation URL 83 | and ID on the control channel to instruct a receiver to terminate a 84 | presentation. 85 | 2. The receiver sends a reply to all associated control channels to inform all 86 | remote peers that a presentation is about to be terminated. 87 | 88 | For receiver initiated termination: 89 | 1. The receiver sends a control message to all associated control channels to 90 | inform all remote peers that a presentation is about to be terminated. 91 | 92 | # Remote Playback API functionality 93 | 94 | The WebRTC framework supports media codec negotiation and real-time media 95 | transport. 96 | 97 | [Issue #3](https://github.com/webscreens/openscreenprotocol/issues/3): Fill in 98 | when Remote Playback requirements are known. 99 | 100 | # Reliability 101 | 102 | WebRTC is designed to be operated in a heterogeneous network environment, using 103 | ICE for address discovery and built-in negotiation/re-negotiation mechanism. 104 | 105 | [Issue #30](https://github.com/webscreens/openscreenprotocol/issues/30): 106 | Get reliability data. 107 | 108 | # Latency to establish a new connection 109 | 110 | There are three sources of latency: 111 | 1. Connecting a reliable channel the first time for ICE negotiation. 112 | 2. Establishing the first Data Channel. 113 | 3. Adding an additional Data Channel on top of an existing peer-to-peer 114 | connection. 115 | 116 | [Issue #31](https://github.com/webscreens/openscreenprotocol/issues/31): 117 | Get connection latency data. 118 | 119 | # Latency to transmit a message 120 | 121 | Data Channel is based on SCTP, which allows for out of order packet delivery and 122 | may improve the latency to deliver presentation connection messages on a 123 | congested or lossy network. 124 | 125 | [Issue #31](https://github.com/webscreens/openscreenprotocol/issues/31): 126 | Get supporting data. 127 | 128 | # Ease of implementation / deployment 129 | 130 | Four major browsers (Chrome/Firefox/Edge/Opera) already implement and ship in 131 | the latest release version. An open source library 132 | [WebRTC.org](https://webrtc.org/) is ready with production level quality. 133 | 134 | A common signaling channel/protocol for exchanging ICE candidates needs to be 135 | defined. 136 | 137 | # Privacy 138 | 139 | By relying on UDP, the IP addresses of both endpoints are visible to network 140 | observers. 141 | 142 | DTLS is used for transport level security. Once DTLS is established, all the 143 | control message and data will be encrypted. 144 | 145 | # IPv4 and IPv6 support 146 | 147 | Data Channel depends on SCTP over UDP, which is supported for both IPv4 and IPv6. 148 | 149 | # Hardware requirements 150 | 151 | Major desktop, laptop, and high-end mobile phone should be able to create single 152 | RTC connection since major browser on desktop and mobile already ship WebRTC. 153 | 154 | [Issue #32](https://github.com/webscreens/openscreenprotocol/issues/32): 155 | Obtain data on hardware requirements. 156 | 157 | # Network and power efficiency 158 | 159 | Maintaining a long-lived Data Channel might not be power efficient. 160 | 161 | [Issue #33](https://github.com/webscreens/openscreenprotocol/issues/33): 162 | Obtain data on network and power efficiency. 163 | 164 | # Standardization status 165 | 166 | Data Channel has a standards track specification in the 167 | IETF [RTCWEB Working Group](https://datatracker.ietf.org/wg/rtcweb/charter/). 168 | 169 | Major browsers already implement and ship Data Channel with interoperability 170 | tested. 171 | 172 | # Security 173 | 174 | A general security study has be done by the IETF RTCWEB working group, see 175 | [Security Overview](https://tools.ietf.org/html/draft-ietf-rtcweb-overview-18#section-5) 176 | 177 | The signaling channel for exchanging SDP must be encrypted to prevent a 178 | man-in-the-middle attack. The DTLS handshake exchanges encryption keys and sets 179 | up an encrypted channel for SCTP. A STUN keepalive can be introduced for 180 | consent freshness. An Identity Provider can be introduced for external 181 | authentication. 182 | 183 | # User Experience 184 | 185 | This should be covered by the latency evaluations above. The relevant user 186 | experience requirements ar met by evaluating: 187 | 1. The latency to establish a presentation connection. 188 | 2. The latency to transmit an application message. 189 | -------------------------------------------------------------------------------- /archive/j-pake.md: -------------------------------------------------------------------------------- 1 | # J-PAKE: Password-Authenticated Key Exchange by Juggling 2 | 3 | Password-Authenticated Key Exchange by Juggling (J-PAKE) is a protocol that 4 | allows secure key exchange channel between two remote parties over an 5 | insecure network solely based on a shared password. 6 | 7 | J-PAKE is standardized by IETF in 8 | [[RFC8236](https://datatracker.ietf.org/doc/rfc8236/)], which defines two 9 | variants of J-PAKE protocol: J-PAKE over Finite Field and J-PAKE over 10 | Elliptic Curve. Their relationship is very similar to the relationship 11 | between DH and ECDH. 12 | 13 | Note that elliptic curve is generally recommended since 14 | elliptic curve cryptography requires much shorter key length than finite field cryptography 15 | to achieve the same level of cryptographic strength. For details, see 16 | [ECDSA: The digital signature algorithm of a better internet](https://blog.cloudflare.com/ecdsa-the-digital-signature-algorithm-of-a-better-internet/). 17 | 18 | ## Protocol Overview 19 | 20 | In this document Alice and Bob denote the prover and the verifier, 21 | respectively. 22 | 23 | ### Protocol Setup 24 | 25 | - `(gn, xn)` denotes a key pair of public key `gn` and a private key `xn`. 26 | - Alice generates two key pairs, `(g1, x1)`, `(g2, x2)`. 27 | - Bob generates two key pairs, `(g3, x3)`, `(g4, x4)`. 28 | - Both Alice and Bob know the shared secret `s`. 29 | - `H()` is a secure cryptographic hash function, e.g. SHA-256. 30 | 31 | *TODO*: investigate the requirements for passcode, to avoid Brute-force attacks 32 | 33 | ### Two Rounds 34 | 35 | J-PAKE protocol has two challenge rounds: 36 | 37 | - Round 1: 38 | - Alice sends `g1`, `g2`, and Zero Knowledge Proof (ZKP) for `x1`, `x2` to Bob 39 | - Bob sends `g3`, `g4`, and ZKP for `x3`, `x4` 40 | - Round 2: 41 | - Alice sends `A = f(g1, g3, g4, x2*s)` and ZKP for `x2*s` 42 | - Bob sends `B = f(g1, g2, g3, x4*s)` and ZKP for `x4*s` 43 | 44 | While these two round requires 2 RTT, 45 | [Section 4](https://tools.ietf.org/html/rfc8236#section-4) in [RFC8236] 46 | shows the three-pass variant, i.e. 1.5 RTT protocol: 47 | 48 | - Alice sends `g1`, `g2`, and Zero Knowledge Proof (ZKP) for `g1`, `g2` to Bob 49 | - Bob sends `g3`, `g4`, `B = f(g1, g2, g3, x4*s)`, and ZKP for `g3`, `g4`, `x4*s` 50 | - Alice sends `A = f(g1, g3, g4, x2*s)` and ZKP for `x2*s` 51 | 52 | The three-pass variant would be simpler to implement, while the two-round variant 53 | could keep symmetric protocol architecture. 54 | 55 | *TODO*: consider which variant would be more suitable for Open Screen Protocol 56 | 57 | ### Common Key Generation 58 | 59 | As a result of two rounds of J-PAKE protocol, both Alice and Bob can 60 | compute the common key with `A, x2, s` or `B, x4, s`. 61 | This step will be done when J-PAKE is used to generate common encryption key 62 | as well as to authenticate each other. 63 | 64 | Generally, it is recommended that the common key should finally be derived 65 | from a Key Derivation Function (KDF). For example, TLS 1.3 66 | [[draft-ietf-tls-tls13-28](https://tools.ietf.org/html/draft-ietf-tls-tls13-28)] 67 | and message encryption for Web Push 68 | [[RFC8291](https://datatracker.ietf.org/doc/rfc8291/)] uses 69 | HMAC-based Key Derivation Function (HKDF) 70 | [[RFC5869](https://datatracker.ietf.org/doc/rfc5869/)] 71 | to generate the common encryption key. 72 | 73 | *TODO*: clarify whether J-PAKE is needed for common key generation or not 74 | in Open Screen Protocol 75 | 76 | ## Incorporating J-PAKE into Open Screen Protocol 77 | 78 | To satisfy 79 | [Privacy and Security requirements](requirements.md#privacy-and-security), 80 | Open Screen Protocol uses J-PAKE protocol so that a controlling UA and a 81 | receiving UA can authenticate each other with a passcode. 82 | 83 | J-PAKE authentication must be done before any other communication messages. 84 | There are a couple of possible schemes to incorporate J-PAKE protocol: 85 | 86 | - to establish a secure connection with a self-signed certificate and 87 | start J-PAKE protocol to authenticate each other 88 | - to establish a TLS/DTLS connection integrated with J-PAKE authentication 89 | 90 | ### J-PAKE over a Secure Connection with a Self-signed Certificate 91 | 92 | Once a connection to exchange messages is established, both UAs can send 93 | messages for J-PAKE protocol; Round 1, Round 2, etc. 94 | 95 | *TODO*: discuss whether using a self-signed certificate could be considered 96 | as secure or not 97 | 98 | ### TLS Integration with J-PAKE 99 | 100 | [[draft-cragie-tls-ecjpake-01](https://datatracker.ietf.org/doc/draft-cragie-tls-ecjpake/)] 101 | (TLS-ECJ-PAKE) proposes use of J-PAKE over Elliptic Curve as the 102 | authentication mechanism in TLS handshake without relying PKI. However, 103 | the Internet-Draft has already expired and has not been updated yet. 104 | 105 | It defines the following extentions in TLS handshake: 106 | 107 | - Sending `g1`, `g2`, and ZKP for `g1`, `g2` in ClientHello 108 | - Sending `g3`, `g4`, and ZKP for `g3`, `g4` in ServerHello 109 | - Sending `B`, and ZKP for `x4*s` in ServerKeyExchange 110 | - Sending `A`, and ZKP for `x2*s` in ClientKeyExchange 111 | 112 | On the other hand, several problems have been pointed out in the IETF TLS 113 | working group mailing list: 114 | 115 | - There has not been any consideration to integrate TLS-ECJ-PAKE into TLS 116 | 1.3 yet. 117 | [[TLS01](https://www.ietf.org/mail-archive/web/tls/current/msg20341.html)] 118 | - A 3 or 4 message handshake of J-PAKE would not be desirable, because 119 | a 2 message exchange could fall into the TLS handshake elegantly. 120 | [[TLS02](https://www.ietf.org/mail-archive/web/tls/current/msg20646.html)] 121 | - It is going to move key exchange role from ClientKeyExchange to 122 | ClientHello, which might remove all ability to do negotiation in TLS. 123 | [[TLS02](https://www.ietf.org/mail-archive/web/tls/current/msg20646.html)] 124 | 125 | Note that TLS 1.3 126 | [[draft-ietf-tls-tls13-28](https://tools.ietf.org/html/draft-ietf-tls-tls13-28)] 127 | offers 1- and 0-RTT handshake protocols and exchanges keys via ClientHello and 128 | ServerHello messages. 129 | 130 | ## Open Source Implementations 131 | 132 | - [Mbed TLS](https://github.com/ARMmbed/mbedtls) has implementation of 133 | TLS-ECJ-PAKE. [OpenThread](https://github.com/openthread/openthread) 134 | refers to Mbed TLS to incorporate TLS-ECJ-PAKE into its protocol stack. 135 | - [Bouncy Castle Cryptography Library](https://www.bouncycastle.org/) has 136 | [Java implementation of J-PAKE over Finite Field](https://www.bouncycastle.org/docs/docs1.5on/org/bouncycastle/crypto/agreement/jpake/package-summary.html). 137 | - Python 3 has implmementation of J-PAKE over Finite Field as a [Python3 module](https://pypi.org/project/jpake/). 138 | - [NSS](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS) had 139 | implementation of J-PAKE over Finite Field used by Firefox Sync, but it 140 | was already discontinued. 141 | 142 | ## Appendix: Protocol Details 143 | 144 | ### J-PAKE over Finite Field 145 | 146 | J-PAKE over Finite Field is based on modular exponentiation like RSA and 147 | DSA. 148 | 149 | - `p` and `q` denote two large primes. 150 | - `Gq` denotes a subgroup of `Zp*` with prime order `q`. 151 | - `g` is a generator for `Gq`. 152 | 153 | #### J-PAKE over Finite Field: Round 1 154 | 155 | - Alice -> Bob: `g1 = g^x1`, `g2 = g^x2`, ZKP for `x1`, `x2` 156 | - Bob -> Alice: `g3 = g^x3`, `g4 = g^x4`, ZKP for `x3`, `x4` 157 | 158 | Regarding a key pair `(D, d)`, ZKP for `d` is calculated by the following 159 | steps: 160 | 161 | - Randomly generate a key pair `(V, v)` (`0 ≤ v ≤ q-1`) 162 | - Generate `c = H(g || V || D || User_ID)`, note that `USER_ID` can be any 163 | pre-shared string 164 | - Compute `r = v - d * c mod q` 165 | 166 | Then Alice sends `V` and `r` as ZKP for `d` to Bob. 167 | 168 | ZKP is verified by the following steps: 169 | 170 | - Verify `1 ≤ D ≤ p-1`, `D^q = 1 mod p`, and `D != 1 mod p` 171 | - Verify `V = g^r * D^c mod p` 172 | 173 | #### J-PAKE over Finite Field: Round 2 174 | 175 | - Alice -> Bob: `A = g^((g1+g3+g4)*x2*s) mod p` and ZKP for `x2*s` 176 | - Bob -> Alice: `B = g^((g1+g2+g3)*x4*s) mod p` and ZKP for `x4*s` 177 | 178 | #### J-PAKE over Finite Field: Common Key Generation 179 | 180 | - Alice computes `Ka = (B/g4^(x2*s))^x2 mod p` 181 | - Bob computes `Kb = (A/g2^(x4*s))^x4 mod p` 182 | 183 | Here, `Ka = Kb = g^((x1+x3)*x2*x4*s) mod p`. 184 | 185 | ### J-PAKE over Elliptic Curve 186 | 187 | J-PAKE over Elliptic Curve may use elliptic curves like NIST P-256, P-384, 188 | P-521, etc. 189 | 190 | - `p` denotes a large prime. 191 | - `E(Fp)` denotes an elliptic curve defined over a finite field `Fp`. 192 | - `G` denotes a generator for the subgroup over `E(Fp)` of prime order `n`. 193 | 194 | #### J-PAKE over Elliptic Curve: Round 1 195 | 196 | - Alice -> Bob: `G1 = G x [x1]`, `G2 = G x [x2]`, ZKP for `x1`, `x2` 197 | - Bob -> Alice: `G3 = G x [x3]`, `G4 = G x [x4]`, ZKP for `x3`, `x4` 198 | 199 | Regarding a key pair `(D, d)`, ZKP for `d` is calculated by the following 200 | steps: 201 | 202 | - Randomly generate a key pair `(V, v)` (`0 ≤ v ≤ n-1`) 203 | - Generate `c = H(G || V || D || User_ID)`, note that `USER_ID` can be any 204 | pre-shared string 205 | - Compute `r = v - d * c mod n` 206 | 207 | Then Alice sends `V` and `r` as ZKP for `d` to Bob. 208 | 209 | ZKP is verified by the following steps: 210 | 211 | - Verify `D` is a valid point on the curve and `D*[h]` is not the point 212 | at infinity (e.g. `h = 1, 2, or 4`) 213 | - Verify `V = G x [r] + D x [c]` 214 | 215 | #### J-PAKE over Elliptic Curve: Round 2 216 | 217 | - Alice -> Bob: `A = (G1+G3+G4) x [x2*s]` and ZKP for `x2*s` 218 | - Bob -> Alice: `B = (G1+G2+G3) x [x4*s]` and ZKP for `x4*s` 219 | 220 | #### J-PAKE over Elliptic Curve: Common Key Generation 221 | 222 | - Alice computes `Ka = (B - (G4 x [x2*s])) x [x2]` 223 | - Bob computes `Kb = (A - (G2 x [x4*s])) x [x4]` 224 | 225 | Here, `Ka = Kb = G x [(x1+x3)*(x2*x4*s)]`. 226 | 227 | ### Key Confirmation 228 | 229 | [Section 5](https://tools.ietf.org/html/rfc8236#section-5) in [RFC8236] 230 | recommends that an additional key confirmation should be performed to 231 | achieve explicit authentication, whenever the network bandwidth allows 232 | it. Note that while this procedure provides explicit assurance of 233 | sharing the common encryption key, it requires one additional RTT. 234 | 235 | *TODO*: discuss whether explicit key confirmation would really be needed or not 236 | 237 | In detail, the following two procedures to confirm the derived key 238 | `k'` have been proposed. 239 | 240 | #### Key Confirmation: The first method 241 | 242 | - Alice -> Bob: `H(H(k'))` 243 | - Bob -> Alice: `H(k')` 244 | 245 | Key Verification defined in 246 | [Mozilla's protocol draft](https://wiki.mozilla.org/WebAPI/PresentationAPI:Protocol_Draft#Device_Pairing) 247 | is based on the first method. 248 | 249 | #### Key Confirmation: The second method 250 | 251 | In the finite field setting: 252 | 253 | - Alice -> Bob: 254 | `HMAC(k', Message_String || ID_Alice || ID_Bob || g1 || g2 || g3 || g4)` 255 | - Bob -> Alice: 256 | `HMAC(k', Message_String || ID_Bob || ID_Alice || g3 || g4 || g1 || g2)` 257 | 258 | In the elliptic curve setting: 259 | 260 | - Alice -> Bob: 261 | `HMAC(k', Message_String || ID_Alice || ID_Bob || G1 || G2 || G3 || G4)` 262 | - Bob -> Alice: 263 | `HMAC(k', Message_String || ID_Bob || ID_Alice || G3 || G4 || G1 || G2)` 264 | 265 | Note that [[RFC8236](https://tools.ietf.org/html/rfc8236)] recommends 266 | the second method because of implementation symmetry. -------------------------------------------------------------------------------- /archive/mdns.md: -------------------------------------------------------------------------------- 1 | # Multicast DNS / DNS Service Discovery 2 | 3 | Multicast DNS (mDNS) and DNS Service Discovery (DNS-SD) are two protocols that 4 | work together to discover services over the local area network by extending 5 | traditional Internet DNS. (For the rest of this document we use mDNS to refer 6 | to both protocols used together.) 7 | 8 | mDNS works on a client-server model. Clients (listeners) send multicast DNS 9 | queries for records representing service instances, and servers (responders) 10 | answer by multicasting matching records that have been registered for each 11 | instance including SRV, PTR, TXT and A/AAAA. These records contain addressing 12 | information and metadata for instances of the requested service. 13 | 14 | Records are sent with a time-to-live (TTL). Listeners may cache records they 15 | receive from previous multicasts to answer future queries locally, but should 16 | periodically refresh these cached records before the TTL expires. 17 | 18 | ## Message Flow 19 | 20 | The following message flow illustrates how queries and records are sent between 21 | mDNS listeners and responders. The listener begins by multicasting a QUERY to 22 | the multicast address 224.0.0.251:5300. Responders that receive the request 23 | respond by multicasting resource records to the same address. (The class, flags 24 | and TTL of these records are omitted for brevity.) 25 | 26 | If a responder is about to disconnect from the network, it multicasts the same 27 | records with a TTL of 0. This instructs listeners that may have cached the 28 | records to discard them. 29 | 30 | ![](images/mdns.png) 31 | 32 | If a responder has updated information to propagate to listeners (for example, a 33 | change in TXT data or IP address), or it has just connected to a network, it can 34 | send an unsolicited multicast of its current resource records with the "cache 35 | flush" bit set to 1. Listeners will overwrite any existing cached records for 36 | that host. More details on cache flush semantics can be found in 37 | [RFC 6762 Section 10.2](https://tools.ietf.org/html/rfc6762#section-10.2). 38 | 39 | ## Example 40 | 41 | The following are example records that could be exchanged between a controlling 42 | user agent and a presentation display using mDNS. The Query is sent from the 43 | controlling user agent, and other records are sent as part of the answer from 44 | the presentation display. Typically all answer records are sent together if 45 | they fit into one packet. All records below have class `IN`. The friendly 46 | names, TTLs, and text record contents are examples for illustration. 47 | 48 | ### Query 49 | 50 | ``` 51 | Flags: 0x0000 (Standard query) 52 | Name: _openscreen._quic.local 53 | Type: PTR (Domain name pointer) 54 | ``` 55 | 56 | ### PTR 57 | 58 | A `PTR` record is a pointer to a specific domain name that can be further 59 | resolved. 60 | 61 | ``` 62 | Type: PTR 63 | Flags: 0x8400 (Authoritative response) 64 | TTL: 5 minutes 65 | Domain Name: Living Room._openscreen._quic.local 66 | ``` 67 | 68 | ### SRV 69 | 70 | A `SRV` record names a service instance running a specific protocol on a port, 71 | in this case the `Living Room` instance running `_openscreen` on port 8009. 72 | 73 | ``` 74 | Type: SRV 75 | Service: Living Room 76 | Protocol: _openscreen 77 | Name: _quic.local 78 | TTL: 5 minutes 79 | Priority: 0 80 | Weight: 0 81 | Port: 8009 82 | Target: Living Room.local 83 | ``` 84 | 85 | ### TXT 86 | 87 | A `TXT` record has arbitrary data about a domain name in a `key`=`value` format 88 | with two-letter keys 89 | ([RFC 6763 Section 6](https://tools.ietf.org/html/rfc6763#section-6)). 90 | In this form, values are limited to 252 bytes. 91 | 92 | ``` 93 | Type: TXT 94 | Name: Livng Room._openscreen._quic.local 95 | TTL: 60 minutes 96 | Text: nm=Living Room TV 97 | Text: id=9b16f21968fabb4d1d00a9f8a741a2dc 98 | Text: 99 | ``` 100 | 101 | ### A/AAAA 102 | 103 | `A` and `AAAA` records contain IP addresses for the named entity. 104 | 105 | ``` 106 | Type: A 107 | Name: Living Room.local 108 | TTL: 5 minutes 109 | Addr: 192.168.0.3 110 | 111 | Type: AAAA 112 | Name: Living Room.local 113 | TTL: 5 minutes 114 | Addr: 2620:0:1009:fd00:1d8a:2595:7e02:61db/64 115 | ``` 116 | 117 | # Design and specification 118 | 119 | Multicast DNS and DNS-SD are defined by two IETF RFCs. 120 | 121 | * [RFC 6762: Multicast DNS](https://tools.ietf.org/html/rfc6762) 122 | * [RFC 6763: DNS-Based Service Discovery](https://tools.ietf.org/html/rfc6763) 123 | 124 | In addition the site [dns-sd.org](http://www.dns-sd.org/) contains more 125 | background information on the use of these protocols, and the book 126 | [Zero Configuration Networking: The Definitive Guide](http://shop.oreilly.com/product/9780596101008.do) 127 | contains additional documentation and example code. 128 | 129 | # Presentation API functionality 130 | 131 | We discuss below how mDNS meets the requirements for 132 | [presentation display availability](requirements.md#presentation-display-availability). 133 | 134 | ## Discovery of presentation displays 135 | 136 | mDNS allows a controlling user agent to discover presentation displays on the 137 | same local area network running a receiver on a given 138 | IP:port. mDNS does not support reliable message exchange, so once the IP:port 139 | is known, the controlling user agent will initiate a control channel to the 140 | receiver using QUIC, TCP, or another reliable transport protocol. The 141 | control channel can then be used for control of presentations and/or 142 | `PresentationConnection` messaging. 143 | 144 | ## Advertisement of friendly name 145 | 146 | mDNS allows a friendly name for the presentation display to be provided in two 147 | ways: 148 | 149 | 1. By setting the Service (hostname) part of the `SRV` record. 150 | 2. By adding an entry to the `TXT` record, i.e. `nm=Living Room TV`. 151 | 152 | However, advertising friendly names through DNS suffers from some inherent 153 | limitations of the DNS protocol. 154 | 155 | First, practically speaking answers are limited by the size of an Ethernet 156 | packet, effectively about 1400 bytes. Some software and routers may further 157 | reject DNS packets over 512 bytes as invalid. This may not be large enough to 158 | encode all friendly names and some may require truncation. 159 | 160 | Second, `SRV` hostnames tend to follow DNS naming conventions, which discourage 161 | special characters and disallow Unicode. 162 | 163 | Only `TXT` records may contain a full Unicode string in UTF-8. Individual `TXT` 164 | values are limited to 255 octets, which may turn out to be a practical 165 | limitation in some character sets. 166 | 167 | ## Query for presentation URL compatibility 168 | 169 | There doesn't appear to be a practical way to do this over mDNS, as an mDNS 170 | query record is not easily extensible to include URLs. It may be possible for 171 | the presentation display to advertise URL patterns in its `TXT` record to allow 172 | controlling user agents to pre-filter presentation displays by URL. 173 | 174 | For mDNS based discovery, querying for URL compatibility must be done using a 175 | separate control channel established to the receiver. 176 | 177 | # Remote Playback API functionality 178 | 179 | Describe how the discovery protocol meets functional requirements for the Remote 180 | Playback API. 181 | 182 | **TODO:** Fill in when Remote Playback requirements are 183 | known. See 184 | [Issue #3](https://github.com/webscreens/openscreenprotocol/issues/3). 185 | 186 | # Reliability 187 | 188 | ## Protocol issues 189 | 190 | mDNS relies on UDP multicast; individual packets (containing queries or 191 | answers) may not be delivered. The implementation of mDNS for 192 | Chrome/Chromecast sends queries and answers three times each to minimize the 193 | chance that packets are dropped. 194 | 195 | There is a risk that listeners have cached data from previous answers that is 196 | out of date (providing the wrong host name, IP address or other metadata). The 197 | mDNS protocol addresses cache coherency by several mechanisms: 198 | * Responders should send unsolicited multicasts of updated data with the "cache 199 | flush" bit set. 200 | * Listeners should attempt to revalidate cached records at 80%, 90%, and 95% of 201 | TTL lifetime. 202 | * If there are other listeners connected to the same network, the listener will 203 | also receive multicast responses to their queries, and can use them to 204 | maintain its cached records. 205 | * The listener should aggressively flush cached records on a network topology 206 | change (interface up/down, change of WiFi SSID, etc.) 207 | 208 | There is also a risk that listeners will cache records for a presentation 209 | display that is no longer connected to the network, especially if the display 210 | was abruptly disconnected. This can be mitigated by using other signals, such 211 | as disconnection or keep-alive failure of the control channel, to track when a 212 | presentation display has disconnected. 213 | 214 | ## Platform issues 215 | 216 | Some operating systems (such as Mac OS X/iOS) implement their own mDNS listener, 217 | or installed software may include an mDNS listener that binds port 5353. A user 218 | agent that implements its own mDNS listener may not be able to run an mDNS 219 | listener on these systems if port 5353 is not bound for shared use. 220 | 221 | mDNS is also subject to general issues affecting multicast discovery. Operating 222 | system configuration, router configuration, and firewall software may block its 223 | operation. Users may not even be aware of the situation, and it can be 224 | difficult or impossible for user agents to determine what component is blocking 225 | mDNS; users will just be unable to discover any presentation displays. 226 | 227 | [Issue #37](https://github.com/webscreens/openscreenprotocol/issues/37): Get 228 | reliability data. 229 | 230 | ## Record caching 231 | 232 | One interesting aspect of mDNS is the ability for intervening layers of software 233 | between the controlling user agent and the presentation display (such as the 234 | underlying controlling user agent OS or the router firmware) to cache mDNS 235 | records and respond to queries, even if the original presentation display is 236 | unable to communicate directly with the controlling user agent. If this is 237 | implemented with correct support for cache coherency, this may improve 238 | reliability by making mDNS more tolerant of transient network interruptions. 239 | 240 | # Latency of device discovery / device removal 241 | 242 | When a presentation display connects to a network, it must advertise itself by 243 | repeately multicasting its resource records with the "cache flush" bit set to 1 244 | ([RFC 6762 Section 8.3](https://tools.ietf.org/html/rfc6762#section-8.3)). This 245 | should give listeners the opporunity to discover newly available displays 246 | shortly after they are attached to a network. However, to meet the requirements 247 | of the specification, a probing step must be completed first to break any naming 248 | ties, which will introduce a delay. 249 | 250 | When presentation display is disconnected from a network, it should similarly 251 | advertise a "goodbye" packet that updates its resource records with a TTL of 252 | zero ([RFC 6762 Section 10.1](https://tools.ietf.org/html/rfc6762#section-10.1)). 253 | If things "work as expected", listeners will delete these records from 254 | their cache on receipt and promptly show the presentation display as 255 | unavailable. 256 | 257 | If the presentation display is abruptly disconnected from the network and is not 258 | able to transmit a goodbye packet, listeners must wait for the expiration of 259 | their cached records to show the display as unavailable. This depends on the 260 | TTL set with these records. 261 | 262 | [Issue #69](https://github.com/webscreens/openscreenprotocol/issues/69): Collect 263 | data on latency of discovery. 264 | 265 | # Network and power efficiency 266 | 267 | The network utilization of mDNS depends on several factors including: 268 | * The number of controlling user agents and presentation displays connected to 269 | the network at any one time. 270 | * The frequency that devices enter and leave the network. 271 | * TTL for mDNS answers and cache behavior on listeners. 272 | * The use of Known Answer suppression, which allows listeners to include 273 | currently cached resource records with their queries. 274 | * Whether all answer records can fit into a single packet. 275 | 276 | Because mDNS behavior is specified, it should be possible to construct a model 277 | of network activity given assumptions about the factors above. 278 | 279 | [Issue #38](https://github.com/webscreens/openscreenprotocol/issues/38): Get 280 | network and power efficiency data. 281 | 282 | # Ease of implementation / deployment 283 | 284 | ## Platform support 285 | 286 | mDNS has been supported on Mac OS X since version 10.2 (released in 2002) under 287 | the brand name Rendezvous (now Bonjour), and iOS since its initial release 288 | in 2007. It has been supported in Android since version 4.1 (Jelly Bean, 289 | released in 2012). On Windows, mDNS is supported for UWP applications in 290 | Windows 10 via 291 | [advertisement](https://docs.microsoft.com/en-us/uwp/api/Windows.Networking.ServiceDiscovery.Dnssd) 292 | and 293 | [device enumeration](https://docs.microsoft.com/en-us/uwp/api/windows.devices.enumeration) 294 | APIs. It is also supported in Chrome OS for Chrome apps via 295 | [chrome.mdns](https://developer.chrome.com/apps/mdns). 296 | 297 | ## Open source implementations 298 | 299 | There are several open source implementations of mDNS listeners and responders. 300 | 301 | Apple maintains [mDNSResponder](https://opensource.apple.com/source/mDNSResponder/), 302 | an open source and cross-platform implementation of mDNS, released under an 303 | Apache 2.0 license. 304 | 305 | [Avahi](https://github.com/lathiat/avahi) is another open source implementation 306 | of mDNS targeted for Linux under GPL 2.1. 307 | 308 | # IPv4 and IPv6 support 309 | 310 | IPv6 is fully supported, as a presentation display can add AAAA records to its 311 | answers to provide IPv6 address(es) for itself. DNS AAAA records are defined by 312 | [RFC 3596: DNS Extensions to Support IP Version 6](https://tools.ietf.org/html/rfc3596). 313 | 314 | # Hardware requirements 315 | 316 | mDNS has been successfully deployed in 2002-era Apple computers, 2012-era 317 | Android devices, Chromecast, and many other embedded devices; no hardware 318 | compatibility constraints are anticipated. 319 | 320 | # Standardization status 321 | 322 | mDNS and DNS-SD are specified by two 323 | [Proposed Standard](https://tools.ietf.org/html/rfc7127) RFCs in the IETF. 324 | Apple has submitted IPR disclosures related to these two RFCs. Ongoing work 325 | continues to evolve DNS-SD in the 326 | [dnssd](https://datatracker.ietf.org/wg/dnssd/about/) IETF working group. 327 | 328 | # Privacy 329 | 330 | The following information may be revealed through mDNS: 331 | * The friendly name of the presentation display. 332 | * IP address(es) and port numbers of a receiver. 333 | * Additional data exposed through `TXT` records, such as: 334 | * A full friendly name. 335 | * URL patterns for compatible presentation URLs. 336 | 337 | # Security 338 | 339 | mDNS is not secure. All devices on the local network can observe all other 340 | devices and manipulate the operation of mDNS. An active attacker with access to 341 | the same LAN can either hide the existence of presentation displays (denial of 342 | service), present false information about displays that do exist (spoofing), or 343 | respond as a fake display/browser and try to get a browser/display to interact 344 | with it (spoofing). 345 | 346 | These issues must be mitigated by other security features of Open Screen such as 347 | device authentication and transport security. 348 | 349 | ## Security History 350 | 351 | The [CVE database](https://cve.mitre.org/index.html) has at least 23 past 352 | vulnerability disclosures related to mDNS. They can be broken down into the 353 | following categories. 354 | 355 | ### Denial of Service 356 | 357 | The most common vulnerability occured when the mDNS responder was unable to 358 | handle an invalid request, resulting in an application crash or other denial of 359 | service. 360 | 361 | * [CVE-2006-2288](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2006-2288) 362 | * [CVE-2007-0613](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2007-0613) 363 | * [CVE-2007-0614](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2007-0614) 364 | * [CVE-2007-0710](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2007-0710) 365 | * [CVE-2008-2326](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-2326) 366 | * [CVE-2008-5081](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-5081) 367 | * [CVE-2009-0758](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-0758) 368 | * [CVE-2011-1002](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2011-1002) 369 | * [CVE-2013-1141](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-1141) 370 | * [CVE-2014-3357](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3357) 371 | * [CVE-2014-3358](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3358) 372 | * [CVE-2015-0650](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-0650) 373 | * [CVE-2017-6520](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-6520) 374 | 375 | ### WAN mDNS responses 376 | 377 | Some mDNS responders were vulnerable because they answered unicast mDNS queries 378 | on their WAN interface, allowing a remote host to query for LAN internal 379 | services and possibly disrupt LAN service discovery through denial of service 380 | attacks. 381 | 382 | * [CVE-2015-1892](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-1892) 383 | * [CVE-2015-2809](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-2809) 384 | * [CVE-2015-6586](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-6586) 385 | 386 | ### Arbitrary Code Execution 387 | 388 | These are the most serious attacks that could lead to a temporary or persistent 389 | exploit of the presentation display by permitting arbitrary code execution. 390 | Below there is a one-line summary of the nature of the exploit when known. 391 | 392 | * [CVE-2007-3744](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2007-3744) - 393 | Related to a port mapping protocol, not mDNS itself. 394 | * [CVE-2007-3828](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2007-3828) 395 | * [CVE-2008-0989](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-0989) - 396 | Format string issue with local hostnames. 397 | * [CVE-2015-7987](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-7987) - 398 | Multiple buffer overflows. 399 | * [CVE-2015-7988](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-7988) 400 | 401 | ### Other 402 | 403 | * [CVE-2008-3630](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-3630) 404 | * [CVE-2014-3290](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3290) 405 | 406 | ### Analysis 407 | 408 | Based on the vulnerability history, mDNS carries a potential risk of two 409 | intersecting vulnerabilities creating a new remote exploit vector: 410 | 1. Presentation display's mDNS responder listens for mDNS queries that originate 411 | from the WAN. 412 | 2. Presentation display's mDNS responder allows remote code execution through a 413 | malformed query. 414 | 415 | To mitigate these risks, any implementation of an mDNS responder should leverage 416 | good security practices, including but not limited to: 417 | 418 | * Sandboxing the process that hosts the mDNS responder to prevent exploits from 419 | gaining access to priveleged system APIs. 420 | * Network and OS-level firewalls to block mDNS queries originating from the WAN. 421 | * Regular security audits of the mDNS responder code, including fuzz testing to 422 | proble handling of malformed input. 423 | * Regular software updates to patch known vulnerabilities. 424 | 425 | # User experience 426 | 427 | * As mentioned in _Reliability_, mDNS may be blocked by system or network 428 | configuration, and it is difficult for end users to diagnose when it fails. 429 | 430 | * As mentioned in _Advertisement of friendly name_, the friendly name discovered 431 | through mDNS may be truncated because of DNS record size limitations. 432 | 433 | * As mentioned in _Latency of device removal_, DNS caching induces a delay 434 | between the disconnection of a presentation display and controlling user 435 | agents updating their display availability information. 436 | 437 | # Notes 438 | 439 | The protocol string `_openscreen._quic` is a placeholder and may not reflect any 440 | actual protocol string chosen for mDNS. For example, if a TCP based transport 441 | is used it would be `_openscreen._tcp` instead. Any chosen protocol string(s) 442 | will need to be registered with the [IANA](https://tools.ietf.org/html/rfc6335). 443 | 444 | DNS service discovery (DNS-SD) is not limited to LAN multicast; service 445 | discovery can also use unicast DNS mechanisms that exist currently for the 446 | Internet, as proposed in e.g. 447 | [Hybrid Unicast/Multicast DNS-Based Service Discovery](https://tools.ietf.org/html/draft-cheshire-mdnsext-hybrid-02). 448 | A mechanism such as this could be used to enable 'guest mode' discovery of 449 | presentation displays for controlling user agents that are not connected to the 450 | same LAN. 451 | -------------------------------------------------------------------------------- /archive/quic.md: -------------------------------------------------------------------------------- 1 | # QUIC 2 | 3 | [QUIC](https://www.chromium.org/quic) is a multiplexed stream transport over 4 | UDP. It advertises the following benefits over TCP: 5 | 6 | - Dramatically reduced connection establishment time 7 | - Improved congestion control 8 | - Multiplexing without head of line blocking 9 | - Forward error correction 10 | - Connection migration 11 | 12 | # Design and Specification 13 | 14 | - [QUIC overview](https://docs.google.com/document/d/1gY9-YNDNAB1eip-RTPbqphgySwSNSDHLq9D5Bty4FSU/edit) 15 | - [QUIC wire specification](https://docs.google.com/document/d/1WJvyZflAO2pq77yOLbp9NsGjC1CHetAXV8I0fQe-B_U/edit) 16 | - IETF draft: [QUIC: A UDP-Based Multiplexed and Secure Transport](https://tools.ietf.org/html/draft-ietf-quic-transport-00) 17 | 18 | # Presentation API functionality 19 | 20 | A QUIC connection between a client and a server transmits data in 21 | [QUIC Streams](https://tools.ietf.org/html/draft-ietf-quic-transport-00#section-6.1). 22 | Each Stream represents a bidrectional reliable sequence of data packets, can 23 | originate from the server or client, and has a unique integer ID. 24 | 25 | For the Presentation API, the most common case is that the controlling user 26 | agent plays the role of the client and the presentation display the role of the 27 | server. 28 | 29 | Assume that a single QUIC connection is used to transmit data between the 30 | controlling user agent and receiver. The following mapping could be used to 31 | associate streams with Presentation API concepts: 32 | 33 | - One reserved stream with ID 5 for control messages between the controlling 34 | user agent and receiver. 35 | - One stream with ID >= 10 for each PresentationConnection. 36 | 37 | Within each stream, an Open Screen specific framing would have to be defined to 38 | allow individual messages to be extracted, similar to how 39 | [HTTP/2 resources](https://tools.ietf.org/html/draft-ietf-quic-http-00) 40 | are mapped to Streams. 41 | 42 | [Issue #62](https://github.com/webscreens/openscreenprotocol/issues/62): If 43 | WebSockets are possible on QUIC, investigate how it is done. 44 | 45 | With this outline, once connection was established, the requirements could be 46 | met as follows: 47 | 48 | ## Presentation Initiation 49 | 50 | 1. Send a control message on Stream 5 from the controlling user agent to the 51 | reciever to start the presentation with ID, URL, and a Stream ID for the 52 | initial presentation connection. 53 | 2. Get a reply on Stream 5 with the ID, URL, and stream ID to confirm success 54 | (or report an error). 55 | 56 | ## Presentation Resumption 57 | 58 | 1. Send a control message on Stream 5 from the controlling user agent to the 59 | receiver reconnect to a presentation with ID, URL, and a Stream ID for the 60 | initial presentation connection. 61 | 2. Get a reply on Stream 5 with the ID, URL, and stream ID to confirm success 62 | (or report an error). 63 | 64 | ## Presentation Connections 65 | 66 | Multiple connections from a controlling user agent can be handled by assigning 67 | unique Stream IDs, and the receiver can use stream IDs to disambiguate the 68 | sources of incoming messages. 69 | 70 | Either side may close the stream it uses to send messages to the destination 71 | browsing context by setting the 72 | [FIN flag](https://tools.ietf.org/html/draft-ietf-quic-transport-00#section-8.1) 73 | in the final QUIC frame on the stream. It can also send a message on Stream 5 74 | indicating the reason why the connection was closed. 75 | 76 | ## Presentation Connection Messaging 77 | 78 | Binary or text messages can be sent on the QUIC Stream corresponding to the 79 | presentation connection. The framing of these messages would need to be 80 | defined. 81 | 82 | ## Presentation Termination 83 | 84 | A controlling user agent can send a control message with URL and ID on Stream 5 85 | to instruct a receiver to terminate a presentation. 86 | 87 | The receiver can send a 88 | [RST_STREAM](https://tools.ietf.org/html/draft-ietf-quic-transport-00#section-6.6) 89 | frame with a custom error code to inform all presentation connections that a 90 | presentation is about to be terminated. 91 | 92 | # Remote Playback API functionality 93 | 94 | TBD once remote playback API requirements are set. 95 | 96 | # Reliability 97 | 98 | [Issue #63](https://github.com/webscreens/openscreenprotocol/issues/63): Get 99 | reliability data. 100 | 101 | # Latency to establish a new connection 102 | 103 | QUIC is designed to minimize the number of round trips needed to establish or 104 | re-establish connections. 105 | 106 | [Issue #66](https://github.com/webscreens/openscreenprotocol/issues/66): Get 107 | connection latency data. 108 | 109 | # Latency to transmit messages 110 | 111 | QUIC allows for out of order packet delivery, which may improve the latency to 112 | deliver presentation connection messages on a congested or lossy network. 113 | 114 | [Issue #66](https://github.com/webscreens/openscreenprotocol/issues/66): Get 115 | message transmission latency data. 116 | 117 | # Ease of implementation / deployment 118 | 119 | QUIC is currently provided as part of the open source Chromium project. The 120 | project includes a simple QUIC server implementation (noted as not performant in 121 | any way). Instructions on how to check out and build it can be found 122 | on [chromium.org](https://www.chromium.org/quic/playing-with-quic). The 123 | implementation does have some dependencies on Chromium core 124 | libraries. 125 | 126 | # Privacy 127 | 128 | By relying on UDP, the IP addresses of both endpoints are visible to network 129 | observers. The plaintext portions of the authentication handshake are also 130 | visible to observers. 131 | 132 | Once authentication is established, the current 133 | [QUIC crypto](https://docs.google.com/document/d/1g5nIXAIkN_Y-7XJW5K45IblHd_L2f5LTaDUDwvZ5L6g/edit) 134 | implementation encrypts full datagrams including all QUIC stream framing 135 | information. 136 | 137 | # IPv4 and IPv6 support 138 | 139 | QUIC depends only on UDP, which is supported for both IPv4 and IPv6. 140 | 141 | # Hardware requirements 142 | 143 | [Issue #64](https://github.com/webscreens/openscreenprotocol/issues/64): Obtain 144 | data on hardware requirements 145 | 146 | # Network and power efficiency 147 | 148 | [Issue #65](https://github.com/webscreens/openscreenprotocol/issues/65): Obtain 149 | data on network and power efficiency 150 | 151 | # Standardization status 152 | 153 | QUIC has a standards track specification in the 154 | IETF [QUIC Working Group](https://datatracker.ietf.org/wg/quic/charter/). Last 155 | call is expected in late 2018. 156 | 157 | *TODO:* Link appropriate IPR policy and any relevant disclosures. 158 | 159 | # Security 160 | 161 | QUIC does not mandate a specific security mechanism to authenticate and encrypt 162 | the transport. Stream 1 is reserved for authentication handshake and 163 | implementations can plug in their own crypto protocol using this stream. 164 | 165 | The 166 | [current standards-track proposal](https://tools.ietf.org/html/draft-ietf-quic-tls-06) 167 | describes how TLS 1.3 is implemented as a crypto protocol for QUIC. As of 168 | October 9, 2017, TLS 1.3 is currently in 169 | [draft #21](https://tools.ietf.org/html/draft-ietf-tls-tls13-21). 170 | 171 | # User Experience 172 | 173 | QUIC allows human readable error messages to be sent with a 174 | [CONNECTION_CLOSE](https://tools.ietf.org/html/draft-ietf-quic-transport-00#section-6.9) 175 | frame. This could be used to surface information via the Presentation API or 176 | the user agent when a presentation connection is closed in an error state. 177 | 178 | # Notes 179 | 180 | QUIC is designed to be a transport for HTTP/2, so Presentation API functions 181 | could be implemented in terms of HTTP/2. This proposal assumes the use of 182 | QUIC directly. 183 | -------------------------------------------------------------------------------- /archive/ssdp.md: -------------------------------------------------------------------------------- 1 | # SSDP 2 | 3 | This document evaluates SSDP as a discovery protocol for the Open Screen 4 | Protocol according to several functional and non-functional requirements. 5 | 6 | SSDP (Simple Service Discovery Protocol) is the first layer in the 7 | [UPnP (Universal Plug and Play) Device Architecture](http://www.upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.1.pdf). 8 | It allows user devices like smartphones or tablets (called _control points_) to 9 | search for other devices or services of interest on the network. 10 | 11 | SSDP is also used as part of other protocols separately from the whole UPnP 12 | stack. One such protocol 13 | is [DIAL (DIscovery And Launch)](http://www.dial-multiscreen.org/), which allows 14 | second-screen devices like smartphones or tablets to discover and launch 15 | applications on first-screen devices like smart TVs, set-top boxes and game 16 | consoles. 17 | 18 | Another example is 19 | [HbbTV 2.0 (Hybrid broadcast broadband TV)](https://www.hbbtv.org/resource-library/), 20 | which extends DIAL to discover HbbTV devices and launch HbbTV applications. 21 | 22 | [Fraunhofer FOKUS](https://www.fokus.fraunhofer.de/fame) has 23 | [proposed](https://github.com/google/physical-web/blob/master/documentation/ssdp_support.md) 24 | the use of SSDP to advertise and find URLs in a local area network, as part of 25 | the [Physical Web Project](https://github.com/google/physical-web). 26 | 27 | 28 | # Design and Specification 29 | 30 | SSDP allows uPnP _root devices_ (that offer services like TVs, printers, etc.) 31 | to advertise services to control points on the network. It also allows control 32 | points to search for devices or services of interest at any time. SSDP specifies 33 | the messages exchanged between control points and root devices. 34 | 35 | SSDP advertisements contain specific information about the service or device, 36 | including its type and a unique identifier. SSDP messages adopt the header 37 | field format of HTTP 1.1. However, the rest of the protocol is not based on 38 | HTTP 1.1, as it uses UDP instead of TCP and it has its own processing rules. 39 | 40 | The following sequence diagram shows the SSDP message exchange between a control 41 | point and root device. 42 | 43 | ![](images/ssdp.png) 44 | 45 | 46 | ## Message Flow 47 | 48 | 1. The root device advertises itself on the network by sending a `NOTIFY` 49 | message of type `ssdp:alive` for each service it offers to the multicast 50 | address `239.255.255.250:1900` with all the information needed to access that 51 | service. Control points listening on the multicast address receive the 52 | message and check the service type (`NT`) header to determine if it is 53 | relevant or not. 54 | 55 | To obtain more information, the control point makes an HTTP request to the 56 | device description URL provided in the `LOCATION` header of the `NOTIFY` 57 | message. The device description is a XML document that contains information 58 | about the device like its friendly name and capabilities, as well as 59 | information about each of the services it offers. 60 | 61 | 1. A control point can search for root devices at any time by sending a 62 | `M-SEARCH` query to the same multicast address. The query contains the search 63 | target (`ST`) header specifying the service type the control point wants. 64 | All devices listening to the multicast address will receive the query. 65 | 66 | 1. When a root device receives a query, it checks the `ST` header against the 67 | list of services offered. If there is a match it replies with a unicast 68 | `M-SEARCH` response to the control point that sent the query. 69 | 70 | 1. When a service is no longer available, the root device multicasts a `NOTIFY` 71 | message of type `ssdp:byebye` with `ST` set to the service type. Control 72 | points can remove the service from any caches. 73 | 74 | # Presentation API functionality 75 | 76 | For the Presentation API, the requirement is the ability to "Monitor Display 77 | Availability" by a controlling user agent as described in [6.4 Interface 78 | PresentationAvailability](https://w3c.github.io/presentation-api/#interface-presentationavailability). 79 | 80 | The entry point in the Presentation API to monitor display availability is the 81 | [PresentationRequest](https://w3c.github.io/presentation-api/#interface-presentationrequest) 82 | interface. The algorithm 83 | [_monitoring the list of available presentation displays_](https://w3c.github.io/presentation-api/#dfn-monitor-the-list-of-available-presentation-displays) 84 | is used in 85 | [PresentationRequest.start()](https://w3c.github.io/presentation-api/#dom-presentationrequest-start) 86 | and in 87 | [PresentationRequest.getAvailability()](https://w3c.github.io/presentation-api/#dom-presentationrequest-getavailability). 88 | Only presentation displays that can open at least one of the URLs passed as 89 | input in the PresentationRequest constructor are considered available for that 90 | request. There are at least three ways SSDP can be used to monitor display 91 | availability for the Presentation API: 92 | 93 | ## Method 1 94 | 95 | Similar to SSDP discovery in DIAL. The main steps are listed below: 96 | 97 | 1. The presentation display device advertises using SSDP the 98 | receiver when it is connected to the network with the service type 99 | `urn:openscreen-org:service:openscreenreceiver:1`. The `ssdp:alive` message 100 | contains a `LOCATION` header which points to the XML device description, 101 | which includes the friendly name, device capabilities, and other device data. 102 | 103 | ``` 104 | NOTIFY * HTTP/1.1 105 | HOST: 239.255.255.250:1900 106 | CACHE-CONTROL: max-age = 1800 [response lifetime] 107 | LOCATION: http://192.168.0.123:8080/desc.xml [device description URL] 108 | NTS: ssdp:alive 109 | SERVER: OS/version UPnP/1.0 product/version 110 | USN: XXX-XXX-XXX-XXX [UUID for device] 111 | NT: urn:openscreen-org:service:openscreenreceiver:1 112 | ``` 113 | 114 | 1. The controlling user agent starts to monitor presentation display 115 | availability by sending an SSDP `M-SEARCH` query with the service type 116 | `urn:openscreen-org:service:openscreenreceiver:1` and waits for responses 117 | from presentation displays. The controlling user agent should wait for 118 | `ssdp:alive` and `ssdp:byebye` messages on the multicast address to keep its 119 | list of available displays up-to-date when a new display is connected or an 120 | existing one is disconnected. 121 | 122 | ``` 123 | M-SEARCH * HTTP/1.1 124 | HOST: 239.255.255.250:1900 125 | MAN: ssdp:discover 126 | MX: 2 [seconds to delay response] 127 | ST: urn:openscreen-org:service:openscreenreceiver:1 128 | ``` 129 | 130 | 1. Each presentation display connected to the network running a receiver replies 131 | to the search request with a SSDP message similar to the `ssdp:alive` 132 | message. 133 | 134 | ``` 135 | HTTP/1.1 200 OK 136 | CACHE-CONTROL: max-age = seconds until advertisement expires e.g. 2 137 | DATE: when response was generated 138 | LOCATION: http://192.168.0.123:8080/desc.xml [device description URL] 139 | SERVER: OS/version UPnP/1.0 product/version 140 | USN: XXX-XXX-XXX-XXX [UUID for device] 141 | ST: urn:openscreen-org:service:openscreenreceiver:1 142 | ``` 143 | 144 | 1. When the controlling user agent receives a response from a newly connected 145 | presentation display, it issues an HTTP GET request to the URL in the 146 | `LOCATION` header to get the device description XML. 147 | 148 | 1. The controlling user agent parses the device description XML, extracts the 149 | friendly name of the display and checks if the display can open one of the 150 | URLs associated with an existing call to `PresentationRequest.start()` or 151 | `PresentationRequest.getAvailability()`. If yes, the presentation display 152 | will be added to the list of available displays, and the result sent back to 153 | pages through the Presentation API. 154 | 155 | 1. When a presentation display is disconnected it should advertise a 156 | `ssdp:byebye` message. 157 | 158 | ``` 159 | NOTIFY * HTTP/1.1 160 | HOST: 239.255.255.250:1900 161 | NT: urn:openscreen-org:service:openscreenreceiver:1 162 | NTS: ssdp:byebye 163 | USN: XXX-XXX-XXX-XXX [UUID for device] 164 | ``` 165 | 166 | *Open questions:* 167 | 168 | 1. How to advertise the endpoint of the Open Screen receiver? One 169 | solution is to use a HTTP header parameter in the response of the HTTP GET 170 | request for device description. DIAL uses this solution to send the endpoint 171 | of the DIAL server in the `Application-URL` HTTP response header. Another 172 | solution is to extend the XML device description with a new element to define 173 | the endpoint. 174 | 175 | 1. How to check if the receiver can present a certain URL or not? One solution 176 | is to extend the XML device description with new elements to allow a receiver 177 | to express its capabilities and the controlling user agent can do the 178 | check. Another possible solution is to ask the receiver using the provided 179 | endpoint by sending the presentation URLs. 180 | 181 | ## Method 2 182 | 183 | This method uses only the SSDP messages without requiring the device description 184 | XML. The presentation request URLs are sent by the controlling user agent in a 185 | new header of the SSDP `M-SEARCH` message. If a receiver can open one of the 186 | URLs, it responds with that URL in the search response. 187 | 188 | The search response also adds new headers for the device friendly name, the 189 | service endpoint, and data on URL compatibility. (Note that Section 1.1.3 of 190 | the UPnP device architecture document allows to use vendor specific headers.) 191 | This method is more efficient and secure since no additional HTTP calls and XML 192 | parsing are required. 193 | 194 | Below are the steps that illustrate this method: 195 | 196 | 1. A new presentation display that connects to the network advertises 197 | the following `ssdp:alive` message. 198 | 199 | ``` 200 | NOTIFY * HTTP/1.1 201 | HOST: 239.255.255.250:1900 202 | CACHE-CONTROL: max-age = 1800 [response lifetime] 203 | NTS: ssdp:alive 204 | SERVER: OS/version product/version 205 | USN: XXX-XXX-XXX-XXX [UUID for device] 206 | NT: urn:openscreen-org:service:openscreenreceiver:1 207 | FRIENDLY-NAME.openscreen.org: TXkgUHJlc2VudGF0aW9uIERpc3BsYXk= [My Presentation Display] 208 | RECEIVER.openscreen.org: 192.168.1.100:3000 209 | PROTOCOLS.openscreen.org: cast,dial 210 | HOSTS.openscreen.org: www.youtube.com,www.netflix.com:1000 211 | ``` 212 | 213 | 1. A controlling user agent sends the following SSDP search message to the 214 | multicast address. 215 | 216 | ``` 217 | M-SEARCH * HTTP/1.1 218 | HOST: 239.255.255.250:1900 219 | MAN: "ssdp:discover" 220 | MX: seconds to delay response 221 | ST: urn:openscreen-org:service:openscreenreceiver:1 222 | ``` 223 | 224 | 1. A presentation display that has a running presentation receiver responds to 225 | the following SSDP message. The `openscreen.org` header fields have the same 226 | meanings as in the advertisement message. 227 | 228 | ``` 229 | HTTP/1.1 200 OK 230 | CACHE-CONTROL: max-age = 1800 [response lifetime] 231 | DATE: [when response was generated] 232 | SERVER: [OS]/[version] 233 | USN: XXX-XXX-XXX-XXX [UUID for device] 234 | ST: urn:openscreen-org:service:openscreenreceiver:1 235 | FRIENDLY-NAME.openscreen.org: TXkgUHJlc2VudGF0aW9uIERpc3BsYXk= [My Presentation Display] 236 | RECEIVER.openscreen.org: 192.168.1.100:3000 237 | PROTOCOLS.openscreen.org: cast,dial 238 | HOSTS.openscreen.org: www.youtube.com,www.netflix.com:1000 239 | ``` 240 | 241 | 1. The display sends the following SSDP message when the receiver is no 242 | longer available. There are no new headers added to the `ssdp:byebye` message. 243 | 244 | ``` 245 | NOTIFY * HTTP/1.1 246 | HOST: 239.255.255.250:1900 247 | NT: urn:openscreen-org:service:openscreenreceiver:1 248 | NTS: ssdp:byebye 249 | USN: XXX-XXX-XXX-XXX [UUID for device] 250 | ``` 251 | 252 | ### Custom headers 253 | 254 | There are four Open Screen specific headers in the advertisement and response: 255 | 256 | Header | Mandatory? | Meaning 257 | --------------|------------|--------- 258 | FRIENDLY-NAME | Yes | base64 encoded, UTF-8 friendly name of the presentation display. 259 | RECEIVER | Yes | The IP address:port of the presentation receiver service being advertised. 260 | PROTOCOLS | No | A comma-delimited list of additional URL protocols *other* than https that are compatible with the receiver. 261 | HOSTS | No | A comma-delimited list of URL hosts that are known to be compatible with the presentation display. 262 | 263 | To ensure that the SSDP response fits into 1400 bytes, the HOSTS header may be 264 | dropped or shortened. (The advertisement example above is approximately 439 265 | bytes.) 266 | 267 | ### Display Compatibility 268 | 269 | The controlling user agent can use the information in the `HOSTS` and 270 | `PROTOCOLS` headers to determine compatibility of some presentation URLs 271 | without requiring a connection to the presentation display. The algorithm 272 | to use these headers is as follows: 273 | 274 | ``` 275 | Given `O`, the origin of a presentation URL: 276 | 277 | IF the protocol of O is 'https', THEN 278 | IF the host of O matches any entry in HOSTS, THEN 279 | RETURN 'compatible' 280 | ELSE 281 | RETURN 'unknown' 282 | ELSE IF the protocol of O does not match an entry in PROTOCOLS, THEN 283 | RETURN 'not compatible' 284 | ELSE 285 | RETURN 'unknown' 286 | ``` 287 | 288 | If the algorithm returns `unknown,` a connection to the display and a query 289 | with the full URL is required to determine compatibility. 290 | 291 | ## Method 3 292 | 293 | This approach is identical to Method 2, except that presentation URL protocols 294 | or hosts are not included in SSDP messages. Only the `RECEIVER.openscreen.org` 295 | header is added to the search response, and additional information from the 296 | receiver (including presentation URL compatibility) is obtained from the 297 | application level protocol implemented on that endpoint. The friendly name may 298 | or may not be included in advertisements, based on a tradeoff between usability, 299 | efficiency and privacy. 300 | 301 | # Remote Playback API functionality 302 | 303 | [Issue #3](https://github.com/webscreens/openscreenprotocol/issues/3): Add 304 | requirements for Remote Playback API. 305 | 306 | # Reliability 307 | 308 | As UDP is unreliable, UPnP recommends sending SSDP messages 2 or 3 times with a 309 | delay of few hundred milliseconds between messages. In addition, the 310 | presentation display must re-broadcast advertisements periodically prior to 311 | expiration of the duration specified in the `CACHE-CONTROL` header (whose 312 | minimum value is 1800s). 313 | 314 | [Issue #68](https://github.com/webscreens/openscreenprotocol/issues/68): Get 315 | reliability data. 316 | 317 | # Latency of device discovery / device removal 318 | 319 | New presentation displays added or removed can be immediately detected if the 320 | controlling user agent listens to the multicast address for `ssdp:alive` and 321 | `ssdp:byebye` messages. 322 | 323 | For search requests, the latency depends on the `MX` SSDP header which contains 324 | the maximum wait time in seconds (and must be between 1 and 5 seconds). SSDP 325 | responses from presentation displays should be delayed a random duration between 326 | 0 and `MX` to balance load for the controlling user agent when it processes responses. 327 | 328 | Chrome sets an `MX` value of 2 seconds for its implementation of SSDP for DIAL 329 | ([code reference](https://cs.chromium.org/chromium/src/chrome/browser/media/router/discovery/dial/dial_service.cc?rcl=43fcb5eb66460fb63755f3a9383e4a6131afcc82&l=103)). 330 | 331 | [Issue #69](https://github.com/webscreens/openscreenprotocol/issues/69): Collect 332 | data on latency of discovery. 333 | 334 | # Network efficiency 335 | 336 | It depends on multiple factors like the number of devices in the network using 337 | SSDP (includes devices that support DLNA, DIAL, HbbTV 2.0, etc.), the number of 338 | services provided by each device, the interval to re-send refreshment messages 339 | (value of `CACHE-CONTROL` header), the number of devices/applications sending 340 | discovery messages. 341 | 342 | # Power efficiency 343 | 344 | This depends on many factors including the method chosen above; Methods 2 and 3 345 | are better than Method 1 regarding power efficiency. In Method 1, the 346 | controlling user agent needs to create and send SSDP search requests, receive 347 | and parse SSDP messages, make HTTP requests to get device descriptions and parse 348 | device description XML to get friendly name and check capabilities. 349 | 350 | In Methods 2 and 3, the controlling user agent needs only to create and send 351 | search requests and receive and parse SSDP messages. 352 | 353 | The way that controlling user agents search for presentation displays has an 354 | impact on power efficiency. If a controlling user agent needs to immediately 355 | react to connection and disconnection of presentation displays, it will need to 356 | continuously receive data on the multicast address, including all SSDP messages 357 | sent by other controlling user agents. (An exception is unicast search response 358 | messages sent to other controlling user agents.) 359 | 360 | If the controlling user agent needs to get only a snapshot of available 361 | displays, then it only needs to send a search message to the multicast address 362 | and listen for search response messages for 2-10 seconds. 363 | 364 | [Issue #26](https://github.com/webscreens/openscreenprotocol/issues/26): Get 365 | network and power efficiency data. 366 | 367 | # Ease of implementation / deployment 368 | 369 | It is very easy to implement the SSDP protocol, as it is based soley on UDP and 370 | the messages are easy to create and parse. Examples of open source implementations: 371 | * [libupnp](http://pupnp.sourceforge.net/) (C Library) 372 | * [peer-ssdp](https://github.com/fraunhoferfokus/peer-ssdp) (Node.js Library) 373 | 374 | # IPv4 and IPv6 support 375 | 376 | SSDP supports IPv4 and IPv6. "Appendix A: IP Version 6 Support" of the UPnP 377 | Device architecture document describes all details about support for IPv6. 378 | 379 | # Hardware requirements 380 | 381 | The SSDP layer of uPnP has been implemented on a variety of consumer hardware 382 | devices generations older than those listed in 383 | the [Sample Device Specifications](device_specs.md). It should be feasible to 384 | implement it on the devices listed there. 385 | 386 | # Standardization status 387 | 388 | SSDP is part of the UPnP device architecture. The most recent version of the 389 | specification is [UPnP Device Architecture 390 | 2.0](http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v2.0.pdf) from 391 | February 20, 2015. The original specification for SSDP was as a standalone 392 | [Internet Draft](https://tools.ietf.org/html/draft-cai-ssdp-v1-03) which expired 393 | in April 2000. 394 | 395 | UPnP/SSDP is used in many products like smart TVs, printers, gateways/routers, 396 | NAS, and PCs. According to [DLNA](https://www.dlna.org/), there are over four 397 | billion DLNA-certified devices available on the market. SSDP is also used in 398 | non-DLNA certified devices that support DIAL and HbbTV 2.0, including smart TVs 399 | and digital media receivers, as well as proprietary products like 400 | [SONOS](http://musicpartners.sonos.com/?q=docs) and [Philips 401 | Hue](https://www.developers.meethue.com/). 402 | 403 | On January 1, 2016, the UPnP Forum assigned their assets to the [Open 404 | Connectivity Foundation 405 | (OCF)](https://openconnectivity.org/resources/specifications/upnp). The OCF 406 | requires [membership and 407 | licensing](https://openconnectivity.org/certification/upnp-certification) to 408 | access the uPnP test suite and obtain uPnP certification for a specific device. 409 | Since Open Screen is explicitly *not* a uPnP defined service, OCF membership 410 | should not be required for Open Screen implementers. 411 | 412 | # Privacy 413 | 414 | The standard UPnP device description exposes parameters about the 415 | device/service, such as its unique identifier, friendly name, software, 416 | manufacturer, and service endpoints. In addition, the SSDP vendor extensions 417 | proposed in Method 2 advertise presentation URLs and friendly names to all 418 | devices on the local area network, which may expose private information in an 419 | unintended way. 420 | 421 | # Security 422 | 423 | SSDP considers local network as secure environment; any device on the local area 424 | network can discover other devices or services. Authentication and data privacy 425 | must be implemented on the service or application level. In our case, the output 426 | of discovery is a list of displays and friendly names, which are available to 427 | all devices on the local area network. If Method 2 is adopted, presentation 428 | URLs and endpoints of receivers are also broadcast. Additional security 429 | mechanisms can be implemented during session establishment and communication. 430 | 431 | ## Security History 432 | 433 | Unfortunately there is a long history of exploits related to inappropriate 434 | exposure of uPnP services to the WAN and poor input handling. The January 2013 435 | paper by security firm Rapid7, [Unplug, Don't 436 | Play](https://drive.google.com/open?id=0B0RlZr4vrjIKbV9FVk0yTGg5dFE) discusses 437 | the exent of these problems. 438 | 439 | Here is a sampling of other papers detailing security issues with uPnp/SSDP: 440 | 441 | * [Vulnerability Note VU#357851](http://www.kb.cert.org/vuls/id/357851): UPnP requests accepted over router WAN interfaces - 30 Nov 2012 442 | * [Millions of devices vulnerable via UPnP - Update](http://www.h-online.com/security/news/item/Millions-of-devices-vulnerable-via-UPnP-Update-1794032.html) - 30 January 2013 443 | * [DEFCON 19 presentation](https://www.defcon.org/images/defcon-19/dc-19-presentations/Garcia/DEFCON-19-Garcia-UPnP-Mapping.pdf) about exploit - 11 September 2014 444 | 445 | Publicly accessible uPnP devices are leveraged by malicious parties to implement 446 | distributed denial of service attacks through SSDP amplification. See [this 447 | article](https://blog.cloudflare.com/ssdp-100gbps/) for a detailed explanation 448 | of how this is done. 449 | 450 | ## Other Exploits 451 | 452 | The CVE database currently lists 453 | [58 vulnerability disclosures](https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=UPNP) 454 | related to uPnP in general. Of these, 455 | [17 vulnerability disclosures](https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=SSDP) 456 | are related specifically to improper handling of SSDP requests or responses. 457 | These can be used to issue denial of service attacks (crashing the device) or 458 | achieve remote code execution. 459 | 460 | ## Mitigations 461 | 462 | Any implementation of SSDP should be code audited for security vulnerabilities, 463 | and undergo 464 | [fuzz testing](https://blog.chromium.org/2012/04/fuzzing-for-security.html) 465 | to evaluate input handling. These implementations should have careful handling 466 | of UDP sockets to prevent WAN exposure. 467 | 468 | Open Screen Protocol implementations of SSDP must be designed to block 469 | amplification attacks, even in the case of firewalls that leave port 1900 open. 470 | Specifically: 471 | 472 | * They MUST ignore any unicast `M-SEARCH` request, that does not arrive via the 473 | IPv4 or IPv6 multicast address. 474 | * They MUST ignore any `M-SEARCH` request whose source IP is not part of the 475 | Open Screen receiver's subnet. 476 | * `M-SEARCH` responses MUST only be sent to IP addresses that are part of the 477 | Open Screen receiver's subnet. 478 | * They MUST ignore any `M-SEARCH` request with a `ST` other than the specific 479 | target for Open Screen. 480 | * Specifically, any request for a `ST` of `ssdp:all` MUST be ignored. 481 | * Open Screen Receivers SHOULD ignore `M-SEARCH` requests from IP addresses that 482 | are not [RFC1918](https://tools.ietf.org/html/rfc1918) or 483 | [RFC4193](https://tools.ietf.org/html/rfc4193.html) private addresses. 484 | Responses SHOULD be sent only to these addresses. 485 | * This restriction SHOULD be end user configurable, as some LANs re-use the 486 | public IP address space. 487 | 488 | # Notes 489 | 490 | * The identifiers `urn:openscreen-org:service:openscreenreceiver:1` and 491 | `openscreen.org` are used for illustrative purposes and may not be the 492 | eventual identifiers assigned for Open Screen presentation services. 493 | -------------------------------------------------------------------------------- /archive/templates/README.md: -------------------------------------------------------------------------------- 1 | # Evaluation Templates 2 | 3 | This folder has a templates with initial criteria to evaluate Open Screen 4 | Protocol alternatives. Discussion should not be restricted by the templates; 5 | when applied, they should be extended as needed on a case by case basis to 6 | capture all of the relevant findings. 7 | 8 | -------------------------------------------------------------------------------- /archive/templates/discovery.md: -------------------------------------------------------------------------------- 1 | # Protocol name 2 | 3 | Describe the discovery protocol at a high level here. 4 | 5 | # Design and specification 6 | 7 | Add links to specifications and design docs. 8 | 9 | # Presentation API functionality 10 | 11 | Describe how the discovery protocol meets 12 | [functional requirements for the Presentation API](../requirements.md#presentation-display-availability) 13 | for presentation display availability. 14 | 15 | # Remote Playback API functionality 16 | 17 | Describe how the discovery protocol meets functional requirements for the Remote 18 | Playback API. 19 | 20 | **TODO:** Fill in when Remote Playback equirements are known. 21 | See [Issue #3](https://github.com/webscreens/openscreenprotocol/issues/3). 22 | 23 | # Reliability 24 | 25 | Data describing reliability in different network requirements. 26 | 27 | # Latency of device discovery / device removal 28 | 29 | Data on the latency of discovering a new presentation display added to the 30 | network, or discovering that a display was disconnected from the network. 31 | 32 | # Network and power efficiency 33 | 34 | Any data about power and network overhead. 35 | 36 | # Ease of implementation / deployment 37 | 38 | Including availability of open source implementations. 39 | 40 | # IPv4 and IPv6 support 41 | 42 | # Hardware requirements 43 | 44 | The minimum specifications needed to use the discovery protocol, and whether 45 | the devices in [Sample Device Specifications](../device_specs.md) are 46 | sufficient. 47 | 48 | # Standardization status 49 | 50 | Describe standardization process, timeline, and link to working group's IPR 51 | policy, if any. 52 | 53 | # Privacy 54 | 55 | What device or application information is exposed to network observers by the 56 | discovery protocol? 57 | 58 | # Security 59 | 60 | Describe any impact on the security of the controlling user agent or 61 | presentation display, including threats and potential mitigations. 62 | 63 | # User experience 64 | 65 | Describe any specific impact on 66 | meeting [user experience requirements](../requirements.md#req-nf3-ux) not covered 67 | by the points above. 68 | 69 | # Notes 70 | -------------------------------------------------------------------------------- /archive/templates/transport.md: -------------------------------------------------------------------------------- 1 | # Transport name 2 | 3 | Describe tranport at a high level here. 4 | 5 | # Design and specification 6 | 7 | Add links to specifications and design docs. 8 | 9 | # Presentation API functionality 10 | 11 | Describe how the transport meets [functional requirements for the Presentation 12 | API](../requirements.md#req-p2-initiation), especially requirements 2-6. 13 | 14 | # Remote Playback API functionality 15 | 16 | Describe how the transport meets functional requirements for the Remote Playback 17 | API. 18 | 19 | **TODO:** Fill in when Remote Playback equirements are known. 20 | See [Issue #3](https://github.com/webscreens/openscreenprotocol/issues/3). 21 | 22 | # Reliability 23 | 24 | Data describing reliability in different network environments. 25 | 26 | # Latency to establish a new connection 27 | 28 | Data on connection establishment latency. 29 | 30 | # Latency to transmit messages 31 | 32 | Data on latency of message transmission. 33 | 34 | # Network and power efficiency 35 | 36 | Any data about power and network overhead. 37 | 38 | # Ease of implementation / deployment 39 | 40 | Including availability of open source implementations. 41 | 42 | # IPv4 and IPv6 support 43 | 44 | # Hardware requirements 45 | 46 | The minimum specifications needed to use the transport, and whether the devices 47 | in [Sample Device Specifications](../device_specs.md) are sufficient. 48 | 49 | # Standardization status 50 | 51 | Describe standardization process, timeline, and link to working group's IPR 52 | policy, if any. 53 | 54 | # Privacy 55 | 56 | What device or application information is exposed to network observers by the 57 | transport? 58 | 59 | # Security 60 | 61 | Describe security architecture and what encryption and authentication mechanisms 62 | are supported. 63 | 64 | # User experience 65 | 66 | Describe any specific impact on 67 | meeting [user experience requirements](../requirements.md#req-nf3-ux) not covered 68 | by the points above. 69 | -------------------------------------------------------------------------------- /benchmarks/README.md: -------------------------------------------------------------------------------- 1 | # Open Screen Benchmarks 2 | 3 | These are "design documents" describing benchmarks that collect data on the 4 | performance and efficiency of Open Screen protocol components. The specific 5 | data will answer questions about efficiency, latency and reliability in the 6 | evaluation templates for [discovery](../templates/discovery.md) 7 | and [transport](../templates/transport.md). 8 | 9 | ## Benchmarks 10 | 11 | The following designs have been submitted: 12 | - [Discovery Protocol Benchmark Design](discovery.md) 13 | - [Transport Protocol Benchmark Design](transport.md) 14 | 15 | ## Results 16 | 17 | Eventually results of these benchmarks will be posted here. 18 | 19 | -------------------------------------------------------------------------------- /benchmarks/discovery.md: -------------------------------------------------------------------------------- 1 | # Discovery Protocol Benchmarks 2 | 3 | The goal of this benchmark design is to create a controlled environment in which 4 | we can gather data on performance, efficiency, and reliability of the two 5 | network discovery protocols proposed for Open Screen: 6 | 7 | * [SSDP](../archive/ssdp.md) 8 | * [mDNS](../archive/mdns.md) 9 | 10 | # Observables 11 | 12 | * Network efficiency & utilization 13 | * Number of packets sent and received per device per minute 14 | * Number of bytes sent and received per device per minute 15 | * Total number of packets and bytes sent per minute 16 | * Peak number of packets and bytes sent per second 17 | * Power efficiency 18 | * Total mW consumed per minute per device 19 | * Reliability 20 | * Percentage of devices found after 10s, 30s, 60s 21 | * Latency 22 | * Time to find all devices 23 | * Time to discover that a device has been connected 24 | * Time to discover that a device has been disconnected 25 | 26 | # Test Environment 27 | 28 | ## Hardware and Operating System 29 | 30 | The test environment will consist of 10 31 | [Raspberry Pi 2 Model B](https://www.adafruit.com/product/2358) 32 | single-board computers with: 33 | * ARM Cortex-A53 1.2 GHz quad-core processor 34 | * 1 GB RAM 35 | * 802.11 b/g/n wireless LAN module (via USB) 36 | 37 | These are similar to Android One smartphones and slightly more powerful than 38 | previous generation streaming devices (see [Device Specs](../device_specs.md)). 39 | 40 | The default operating system for Raspberry Pi devices is 41 | [Raspbian](https://www.raspberrypi.org/downloads/raspbian/), which is 42 | Linux-based. The "Lite" version should be sufficient as we don't need an 43 | interactive OS. 44 | 45 | ## Networking 46 | 47 | The test devices will be connected via a 802.11/n, 2.4 GHz WiFi network secured 48 | by WPA2-PSK and provided by an off the shelf, basic home Wi-Fi router. 49 | 50 | Typical models: 51 | * [Netgear N300](https://www.netgear.com/home/products/networking/wifi-routers/WNR3500L.aspx) 52 | * [TP-Link TL-WR841N](http://www.tp-link.com/us/products/details/cat-5506_TL-WR841N.html) 53 | * [ASUS RT-N12 D1](https://www.asus.com/us/Networking/RTN12_D1/) 54 | * [Zyxel NBG-418N v2](http://www.zyxel.com/us/en/products_services/Wireless-N300-Home-Router-NBG-418N-v2/) 55 | 56 | For the sake of reproducibility, we will re-run benchmarks with multiple router 57 | models to see if there is any signficant variation in results. 58 | 59 | ## Software 60 | 61 | For mDNS, we will use the [Avahi](https://www.avahi.org/) open source mDNS 62 | software that is available as a Debian package. 63 | 64 | For SSDP, we will either: 65 | 66 | 1. Fork and customize [libupnp](http://pupnp.sourceforge.net/) for the 67 | [Open Screen SSDP discovery protocol](../archive/ssdp.md). 68 | 2. Write our own SSDP implementation from scratch, possibly based on the 69 | [Chromium](https://cs.chromium.org/chromium/src/chrome/browser/media/router/discovery/dial/dial_service.h) 70 | implementation or the [Fraunhofer FOKUS](https://github.com/fraunhoferfokus/peer-ssdp/blob/master/lib/peer-ssdp.js) 71 | SSDP implementation based on Node.js. 72 | 73 | As part of these implementations, we will instrument them to log data related to 74 | the Observables above, including (but not limited to): 75 | * Packets and bytes sent and received each second 76 | * Timestamp a device is discovered 77 | * Timestamp a device is detected to have left the network 78 | * Number of devices discovered 79 | 80 | A Python script will be used to start the sender and responder process with 81 | command line flags to adjust behavior for a given test condition. Data points of 82 | interest will be logged by the binaries to stdout, which will be injested and 83 | accumulated by the Python script. At the end of the test, the script will write 84 | a JSON file to be copied to a Web server, so that a HTML frontend can be used to 85 | render nice charts of the results. All of the scripts and source code for the 86 | benchmarks will be stored on GitHub. 87 | 88 | # Experimental Variables 89 | 90 | The following variables will be adjusted and the Observables collected for each 91 | condition. 92 | 93 | To keep the number of conditions within reason, one set of parameters will be 94 | adjusted and the others kept fixed. In case the data shows interesting trends, 95 | we can run more conditions as desired as the entire process will be automated 96 | through scripting. 97 | 98 | ## Protocols in use 99 | 100 | * SSDP alone 101 | * mDNS alone 102 | * SSDP and mDNS together 103 | 104 | ## Device Population 105 | 106 | * Number of senders (devices initiating queries): 1, 2, 4, 8 107 | * Number of responders (devices responding to queries): 1, 2, 4, 8 108 | 109 | ## Physical Positioning 110 | 111 | Most benchmarks will take place with the devices co-located (same room, same 112 | distance from router). 113 | 114 | However, to simulate signal fading effects, we will also collect data when the 115 | devices will be positioned in adjacent offices such that the senders are in one 116 | room separated by a wall from the router, and the responders are in a different 117 | room separated by a wall from the router. This is to simulate a typical 118 | household where controller devices, receiver devices, and routers are spread 119 | among different rooms. 120 | 121 | **NOTE:** If there is interest in evaluating these protocols in particularly 122 | adverse WiFi conditions, we can investigate using a routing proxy to simulate 123 | additional congestion and packet loss, or simply move devices further away. 124 | 125 | ## SSDP specific 126 | 127 | * Interval between `M-SEARCH` requests. 128 | * Value of `MX` which is the maximum delay in an `M-SEARCH` response. 129 | 130 | ## mDNS specific 131 | 132 | * TTL assigned to mDNS answers. 133 | 134 | # Data Collection And Analysis 135 | 136 | For numerical values, data will be collected for a given experimental condition 137 | N = 30 times and the 50%, 75%, and 95% values computed, as well as time series. 138 | 139 | One experimental condition (the control) will have no senders or responders to 140 | collect baseline data. 141 | 142 | # Notes / Future Work 143 | 144 | ## Mobile Device Benchmarking 145 | 146 | Power consumption measurement only makes sense as a relative measurement, and 147 | depends heavily on the power saving capabilities of a specific device. We need 148 | to revisit this by designing power benchmarks that can be run on mobile phones and 149 | mobile OSes (Android, iOS). As a first approximation we can allow discovery to run 150 | to a steady state and look at the resulting battery level. 151 | 152 | [Issue #72](https://github.com/webscreens/openscreenprotocol/issues/72): 153 | Investigate power consumption measurement 154 | 155 | ### SSDP 156 | 157 | For benchmarking on mobile devices (e.g., for power consumption), the 158 | [Fraunhofer FOKUS Cordova Plugin](https://github.com/fraunhoferfokus/cordova-plugin-hbbtv/tree/master/src/android/ssdp) 159 | can be used as an SSDP responder. 160 | 161 | ## Steady State Benchmarks 162 | 163 | The benchmarks proposed here are intended to run over the course of several minutes, 164 | until discovery hits a "steady state" and no new devices are discovered. Benchmarks 165 | of network efficiency over the course of hours would also be informative, as most of 166 | the time devices on a network exist in a steady state. For these benchmarks, 167 | different protocol-specific parameters may need to be investigated like `CACHE-CONTROL` 168 | for SSDP. 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /benchmarks/transport.md: -------------------------------------------------------------------------------- 1 | # Transport Protocol Benchmarks 2 | 3 | The goal of this benchmark design is to create a controlled environment in which 4 | we can gather data on performance, efficiency, and reliability of the two 5 | network trasnport protocols proposed for Open Screen: 6 | 7 | * [QUIC](../archive/quic.md) 8 | * [RTC DataChannel](../archive/datachannel.md) 9 | 10 | # Observables 11 | 12 | * Network efficiency & utilization 13 | * Number of packets and bytes exchanged per connection established 14 | * Number of packets and bytes exchanged per control message 15 | * Number of packets and bytes exchanged per application message 16 | * Total packets and bytes for a typical presentation session 17 | * Peak number of packets and bytes sent per second 18 | * Power efficiency 19 | * Total mW consumed per minute per device for a typical presentation session 20 | * Reliability 21 | * Ratio of successful connections per attempt 22 | * Ratio of messages successfully transmitted per attempt 23 | * Frequency of dropped connections 24 | * Latency 25 | * Time to initiate a new connection 26 | * Time to transmit a control message (from first byte sent to last byte received) 27 | * Time to transmit an application message (from first byte sent to last byte received) 28 | 29 | # Test Environment 30 | 31 | ## Hardware and Operating System 32 | 33 | The test hardware will be identical to that for the [discovery 34 | benchmarks](discovery.md). 35 | 36 | ## Networking 37 | 38 | The test network will be identical to that for the [discovery 39 | benchmarks](discovery.md). 40 | 41 | ## Software 42 | 43 | ### QUIC 44 | 45 | The QUIC implementation (both client and server) is part of the Chromium open 46 | source project. Driver binaries will need to be written to create QUIC 47 | connections, and the result compiled for the Raspberry PI platform. 48 | 49 | QUIC crypto will be disabled or set to a trivial implementation initially. When 50 | a transport authentication protocol is defined, it will be converted to use that 51 | protocol and new data collected. 52 | 53 | The QUIC implementation will be instrumented to log data related to the 54 | Observables above, including (but not limited to): 55 | * Packets and bytes sent and received per second 56 | * Packets and bytes sent and received per message 57 | * Packets and bytes sent and received per connection 58 | * Timestamps a connection was initiated and when it was connected 59 | * Timestamps a message was sent and received 60 | * Timestamps of any errors encountered (connection failed, message failed) 61 | 62 | A Python script will be used to start the client and server process with command 63 | line flags to adjust behavior for a given test condition. Data collection will 64 | happen as described in the [discovery benchmark](discovery.md). 65 | 66 | ### RTC DataChannel 67 | 68 | RTC DataChannel is implemented by WebRTC. A binary driver that understands the 69 | same command line flags as the QUIC driver will need to be written. The driver 70 | will include the WebRTC library and a client and server for the bootstrap 71 | channel. 72 | 73 | [Issue #73](https://github.com/webscreens/openscreenprotocol/issues/73): Define 74 | boostrap mechanism for RTCDataChannel. 75 | 76 | WebRTC exposes byte level statistics for individual data channels through its 77 | [API](https://w3c.github.io/webrtc-stats/#dcstats-dict*), although not 78 | packet-level statistics, which will require modification of WebRTC. 79 | 80 | # Experimental Variables 81 | 82 | The following variables will be adjusted and the Observables collected for each 83 | condition. 84 | 85 | To keep the number of conditions within reason, one set of parameters will be 86 | adjusted and the others kept fixed. In case the data shows interesting trends, 87 | we can run more conditions as desired as the entire process will be automated 88 | through scripting. 89 | 90 | ## Protocols in use 91 | 92 | * QUIC 93 | * Bootstrap channel + RTCDataChannel 94 | 95 | ## Device Population 96 | 97 | * Number of controllers per receiver: 1, 2, 4, 8, 16 98 | 99 | ## Physical Positioning 100 | 101 | We will test two conditions: 102 | 103 | * All devices all co-located in the same room 104 | * Controllers in one room, router in a second room, and receiver in a third room. 105 | 106 | ## Message type and sequence 107 | 108 | We will run through the following sequence of connections and messages: 109 | 110 | 1. First controller initiates a connection to the receiver. 111 | 1. First controller initiates a presentation on the receiver. 112 | 1. First controller begins sending a sequence of messages `N` seconds apart to 113 | the receiver. Each message is a random length averaging `S` bytes. 114 | 1. After a random delay averaging `M` seconds, subsequent controllers will make 115 | additional connections to the receiver and begin sending their own messags. 116 | 1. Receiver echoes all messages received back to the controller. 117 | 118 | The following parameters will be varied: 119 | * Delay between connection initiation (`M`) 120 | * Average delay between messages (`M`) 121 | * Average message size (`S`) 122 | 123 | **NOTE**: For large `S`, small `M`, and multiple simultaneous controllers, we 124 | may hit network bandwidth or platform limitations of the receiver. 125 | 126 | # Data Collection And Analysis 127 | 128 | For numerical values, data will be collected for a given experimental condition 129 | N = 30 times and the 50%, 75%, and 95% values computed, as well as time series. 130 | 131 | One experimental condition (the control) will have no connections to collect 132 | baseline data. 133 | 134 | # Notes / Future Work 135 | 136 | ## Mobile Device Benchmarking 137 | 138 | See [Issue #72](https://github.com/webscreens/openscreenprotocol/issues/72). 139 | 140 | ## Multi-receiver cases 141 | 142 | The current design considers one receiver (running one presentation) and 143 | multiple controllers. It may be worth considering adding a second receiver; 144 | however, the network behavior for the trasnport layer is point-to-point and not 145 | multicast, so we do not expect to observe any significant differences in 146 | benchmarks for the second receiver. 147 | -------------------------------------------------------------------------------- /biblio.json: -------------------------------------------------------------------------------- 1 | { 2 | "iso18004": { 3 | "href": "https://iso.org/standard/62021.html", 4 | "title": "Information technology — Automatic identification and data capture techniques — QR Code bar code symbology specification", 5 | "status": "Published", 6 | "publisher": "ISO/IEC", 7 | "isoNumber": "ISO 18004:2015", 8 | "rawDate": "2015-02" 9 | }, 10 | "ITU-R-BT.1359-1": { 11 | "href": "https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.1359-1-199811-I!!PDF-E.pdf", 12 | "title": "ITU-R BT.1359-1, Relative Timing of Sound and Vision for Broadcasting", 13 | "status": "Recommendation", 14 | "publisher": "ITU", 15 | "rawDate": "1998-11" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /capabilities.md: -------------------------------------------------------------------------------- 1 | # Open Screen Protocol Capabilities Registry 2 | 3 | This registry lists the known protocol capabilities used in the [Open Screen 4 | Protocol](https://webscreens.github.io/openscreenprotocol/). An Open Screen 5 | agent uses capabilities to inform other agents which protocol messages it 6 | understands. 7 | 8 | Capability values 1-999 are reserved for use by the Open Screen Protocol itself. 9 | They are listed here for completeness, but are more fully described in the [Open 10 | Screen Protocol](https://webscreens.github.io/openscreenprotocol/#transport). 11 | 12 | ## Open Screen Protocol Capabilities 13 | 14 | | Id | Name | Description | Message Type IDs | 15 | |----|---------------------------|-----------------------------|-----------------------| 16 | | 1 | `receive-audio` | Audio Receiver | 22 | 17 | | 2 | `receive-video` | Video Receiver | 23 | 18 | | 3 | `receive-presentation` | Presentation API Receiver | 14,16,104,106,109,113 | 19 | | 4 | `control-presentation` | Presentation API Controller | 15,16,103,105,107,108,110,113,121 | 20 | | 5 | `receive-remote-playback` | Remote Playback Receiver | 17,19,115,117,119 | 21 | | 6 | `control-remote-playback` | Remote Playback Controller | 18,20,21,114,116,118 | 22 | | 7 | `receive-streaming` | Streaming Receiver | 122,124,127,129,131 | 23 | | 8 | `send-streaming` | Streaming Sender | 123,125,126,128,130,132 | 24 | | 9 | `receive-data` | Data Receiver | 24 | 25 | 26 | ## Extension Capabilities 27 | 28 | This table lists capabilities that other parties have reserved to extend the 29 | core protocol. Each extension should reserve a range of message type IDs and/or 30 | a list of additional fields that will be added to existing Open Screen 31 | Messages. (The entry below is just an example and not an actual registered 32 | extension.) 33 | 34 | | Id | Name | Organization | Description | Message Type IDs | 35 | |------|---------------------|---------------|------------------------|-----------------------| 36 | | 1000 | `frobinate-xyzzy` | FrobozzCo | Adds xyzzy capability | 49-51, 8193-8199 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /code-style.html: -------------------------------------------------------------------------------- 1 | 64 | -------------------------------------------------------------------------------- /device_specs.md: -------------------------------------------------------------------------------- 1 | # Sample Device Specifications 2 | 3 | This document lists specifications for the types of devices that run controlling 4 | user agents or serve as presentation displays implementing the Open Screen 5 | Protocol. 6 | 7 | Below are a selection of older (2015) and lower-end devices to serve as a 8 | baseline for future evaluation, under the assumption that newer and more capable 9 | devices would not be likely to encounter hardware limitations. 10 | 11 | ## Controller Devices 12 | 13 | ### [Android One First Generation](https://en.wikipedia.org/wiki/Micromax_Canvas_A1) 14 | 15 | - CPU: Mediatek MT6582 quad-core ARM Cortex-A7 @ 1.3 GHz 16 | - 1GB DRAM 17 | - 4GB flash 18 | - 802.11 b/g/n WiFi 19 | 20 | *TODO: Low end PC?* 21 | 22 | ## Receiver Devices 23 | 24 | ### [Roku 3 4200](https://en.wikipedia.org/wiki/Roku#Third_generation) 25 | 26 | - CPU: BCM11130 dual core ARM Cortex-A9 @ 900 MHz 27 | - 512MB DDR3 DRAM 28 | - 256MB flash 29 | - 100base-T Ethernet 30 | - 802.11 a/b/g/n dual-band WiFi 31 | 32 | ### [Amazon Fire TV Stick First Generation](https://en.wikipedia.org/wiki/Amazon_Fire_TV#First_generation_2) 33 | 34 | - CPU: BCM28145 dual-core ARM Cortex-A9 @ 1.2GHz 35 | - 1GB DRAM 36 | - 8GB flash 37 | - 802.11 b/g/n dual-band WiFi 38 | 39 | ### [Raspberry PI 2 Model B2](https://en.wikipedia.org/wiki/Raspberry_Pi#Specifications) 40 | 41 | - CPU: BCM2836 32-bit quad-core ARM Cortex-A7 @ 900 MHz 42 | - 1GB DRAM 43 | - 10/100base-T Ethernet via USB 44 | 45 | ### [Sony KDL-43W756C Smart 43-inch Full HD TV (Android TV)](https://www.sony.co.uk/electronics/support/televisions-projectors-lcd-tvs-android-/kdl-43w756c/specifications) 46 | 47 | - CPU: MediaTek MT5890 32-bit dual-core ARM Cortex-A17 @ 1 GHz 48 | - Memory ? 49 | - IEEE 802.11 a/b/g/n WiFi 50 | - 10BASE-T / 100BASE-TX Ethernet 51 | - [More details](https://www.displayspecifications.com/en/model/7e5a14a) 52 | 53 | *TODO: Android TV stick* 54 | -------------------------------------------------------------------------------- /explainer.md: -------------------------------------------------------------------------------- 1 | # Open Screen Protocol Explainer 2 | 3 | The Open Screen Protocol allows one networked device to discover another on the 4 | local network, create a secure connection, and request that the other device 5 | render an application or streaming media using Web APIs such as the 6 | [Presentation API](https://w3c.github.io/presentation-api/) and [Remote Playback 7 | API](https://w3c.github.io/remote-playback/). 8 | 9 | We call devices that implement this protocol Open Screen Agents. 10 | 11 | ## Why should users care? 12 | 13 | Currently there are several proprietary solutions that allow media accessed on 14 | one device to be played on a different device. Examples include [Google 15 | Cast](https://developers.google.com/cast/), [Apple 16 | AirPlay](https://www.apple.com/airplay/), and [Spotify 17 | Connect](https://www.spotify.com/us/connect/). 18 | 19 | However, the application, browser and/or OS largely determine what devices work 20 | together for media playback. The choice of one device, OS or browser largely 21 | determines what other media devices are compatible for launching Web 22 | applications and remote media playback. This in turn may force users into using 23 | specific devices, OSes, or browsers in order to take advantage of second screen 24 | functionality. It also prevents some browsers from implementing second screen 25 | Web APIs at all. 26 | 27 | ## Why should Web developers care? 28 | 29 | Web developers who want to integrate second screen functionality into their 30 | applications currently need to write different code for each browser to 31 | interface with the devices supported by that browser. This discourages wide 32 | adoption of remote playback functionality. For applications that do add second 33 | screen support, they tend to pick one device type versus integrating multiple 34 | device-specific SDKs into their application. 35 | 36 | One goal of Second Screen APIs is to allow developers to write one application 37 | for remote media playback and expect it to function as expected across as many 38 | devices and browsers as possible. 39 | 40 | ## Assumptions and Goals 41 | 42 | The primary goal of the Open Screen Protocol is to provide a complete network 43 | protocol to allow devices from different vendors to implement second screen 44 | APIs and work together. 45 | 46 | The protocol specifically targets the [requirements of second screen Web 47 | APIs](requirements.md): the [Remote Playback 48 | API](https://w3c.github.io/remote-playback/) and the [Presentation 49 | API](https://w3c.github.io/presentation-api/). 50 | 51 | A design goal is to re-use existing network and data standards like mDNS, QUIC 52 | and CBOR as building blocks, versus inventing our own. 53 | 54 | The protocol also provides [security and privacy 55 | guarantees](requirements.md#privacy-and-security), especially with regards to 56 | other devices on the network. 57 | 58 | We assume that the protocol should work on devices with [low-end CPUs and 59 | constrained memory](device_specs.md), which are typical in special purpose 60 | devices like smart TVs and connected speakers. We also assume the protocol will 61 | be used on [battery-powered devices](requirements.md#hardware-and-efficiency). 62 | 63 | ## Non-Goals 64 | 65 | A non-goal is to enable every Web application to be able to successfully render 66 | content on every Open Screen Protocol device. Devices have a wide range of 67 | rendering capabilities and policies about what content they wish to support. 68 | The protocol allows devices to indicate whether they are compatible with a 69 | specific URL or media type. 70 | 71 | ## Alternatives Considered 72 | 73 | We considered adopting an existing protocol like 74 | [Google Cast](https://developers.google.com/cast/), 75 | [DIAL](http://www.dial-multiscreen.org/home), 76 | or [HbbTV 2.0](https://www.hbbtv.org/news-events/hbbtv-2-0-specification-released/) 77 | instead of inventing a new protocol from scratch. However these have significant 78 | limitations that motivated the development of a new protocol: 79 | 80 | * They were not free to implement by other vendors. 81 | * They did not fully support the Web APIs as written. 82 | * They did not have a security model that met the requirements of the Web APIs. 83 | * They would be harder to extend to anticipated future use cases, 84 | like cross-LAN support, or future cross-device Web APIs. 85 | 86 | ## Protocol Overview 87 | 88 | An interaction between Open Screen agents consists of the following phases. 89 | 90 | *Phase 1.* Discovery and connection. 91 | 92 | Initially, an agent _S_ [advertises itself using 93 | mDNS](https://w3c.github.io/openscreenprotocol/#discovery) as available for 94 | other agents to connect to. Another agent, _C_, [initiates a connection](https://w3c.github.io/openscreenprotocol/#transport) using QUIC to the port and IP address advertised by _S_. 95 | 96 | *Phase 2.* Authentication. 97 | 98 | [TLS 1.3 is used to secure the 99 | connection](https://w3c.github.io/openscreenprotocol/#tls-13) between _C_ and 100 | _S_. If _C_ and _S_ have not authenticated before, they negotiate one party to 101 | present a one-time code and the other party to accept the code. (Typically the 102 | end user is asked to input into _C_ a code presented on the screen of 103 | _S_.) [SPAKE2 is used to generate a shared 104 | secret](https://w3c.github.io/openscreenprotocol/#authentication-with-spake2) 105 | and verify the identities of the TLS 1.3 endpoints. 106 | 107 | *Phase 3.* Capability exchange. 108 | 109 | Once the connection is authenticated, 110 | [the two agents exchange capabilities](https://w3c.github.io/openscreenprotocol/#metadata), 111 | which map to sets of messages that each agent understands. For example, one 112 | agent may be an initiator of media remote playback, and the other agent may be 113 | the receiver of remote playback requests. 114 | 115 | Some capabilities are defined by the spec corresponding to the needs of the 116 | Remote Playback API and Presentation API. However, the [set of capabilities is 117 | open ended](https://w3c.github.io/openscreenprotocol/#protocol-extensions) and 118 | may be extended to accomodate future requirements, additional Web APIs, or 119 | device-specific features. 120 | 121 | *Phase 4.* API-specific usage. 122 | 123 | Once the two agents have learned each other's capabilities, they can exchange 124 | messages at the request of Web applications through supported Web APIs. 125 | 126 | For example, if _C_ wishes to [start a presentation](https://w3c.github.io/openscreenprotocol/#presentation-api) on _S_, it would: 127 | 128 | 1. Send a `presentation-url-availability-request` to learn if _S_ can use the URL to start a presentation. 129 | 2. Send a `presentation-start-request` to request that _S_ start a presentation with the URL. 130 | 3. Send and receive `presentation-connection-message`s to exchange messages with the active presentation. 131 | 4. Disconnect from the presentation with `presentation-connection-close-event` or request its termination with `presentation-termination-request`. 132 | 133 | All messages that are specific to the Open Screen Protocol are encoded with CBOR 134 | which provides a good tradeoff between performance, conciseness and Web compatibility. 135 | 136 | 137 | ## Privacy and security 138 | 139 | The protocol is responsible for enabling a secure network connection between two 140 | Open Screen agents. The spec includes guidelines for the presentation and 141 | consumption of the pairing code, how agents can track other agents that have 142 | been previously authenticated, and when an agent should be reauthenticated. 143 | 144 | Other aspects of security and privacy for second screen applications using the 145 | protocol are covered in other specifications, handled by specific agent 146 | implementations, or may be in scope for future revisions of the protocol. 147 | 148 | ## Relationship to other Web specifications 149 | 150 | [WebRTC-QUIC](https://w3c.github.io/webrtc-quic/) is a proposal to enable Web 151 | applications to create peer-to-peer QUIC connections. This could enable 152 | applications to implement parts of the Open Screen Protocol in script. 153 | 154 | [WebTransport](https://w3c.github.io/webtransport/) allows Web applications to 155 | construct HTTP/3 connections to servers. It may be possible to implement parts 156 | of the Open Screen protocol in application script on top of an HTTP/3 157 | WebTransport. 158 | 159 | With either of these capabiliites, applications still cannot discover and 160 | authenticate to Open Screen agents on their own. Those aspects would need to be 161 | handled by the user agent, or new APIs developed to enable Web applications to 162 | take them on. 163 | -------------------------------------------------------------------------------- /images/mdns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c/openscreenprotocol/a438c32c21ee9998acb491af6194531cc6755a16/images/mdns.png -------------------------------------------------------------------------------- /images/schemes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c/openscreenprotocol/a438c32c21ee9998acb491af6194531cc6755a16/images/schemes.png -------------------------------------------------------------------------------- /images/ssdp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c/openscreenprotocol/a438c32c21ee9998acb491af6194531cc6755a16/images/ssdp.png -------------------------------------------------------------------------------- /messages_appendix.cddl: -------------------------------------------------------------------------------- 1 | ; type key 10 2 | agent-info-request = { 3 | request 4 | } 5 | 6 | ; type key 11 7 | agent-info-response = { 8 | response 9 | 1: agent-info ; agent-info 10 | } 11 | 12 | ; type key 120 13 | agent-info-event = { 14 | 0: agent-info ; agent-info 15 | } 16 | 17 | agent-capability = &( 18 | receive-audio: 1 19 | receive-video: 2 20 | receive-presentation: 3 21 | control-presentation: 4 22 | receive-remote-playback: 5 23 | control-remote-playback: 6 24 | receive-streaming: 7 25 | send-streaming: 8 26 | ) 27 | 28 | agent-info = { 29 | 0: text ; display-name 30 | 1: text ; model-name 31 | 2: [* agent-capability] ; capabilities 32 | 3: text ; state-token 33 | 4: [* text] ; locales 34 | } 35 | 36 | ; type key 12 37 | agent-status-request = { 38 | request 39 | ? 1: status ; status 40 | } 41 | 42 | ; type key 13 43 | agent-status-response = { 44 | response 45 | ? 1: status ; status 46 | } 47 | 48 | status = { 49 | 0: text ; status 50 | } 51 | 52 | request = ( 53 | 0: request-id ; request-id 54 | ) 55 | 56 | response = ( 57 | 0: request-id ; request-id 58 | ) 59 | 60 | request-id = uint 61 | 62 | microseconds = uint 63 | 64 | epoch-time = int 65 | 66 | media-timeline = float64 67 | 68 | media-timeline-range = [ 69 | start: media-timeline 70 | end: media-timeline 71 | ] 72 | 73 | ; type key 1001 74 | auth-capabilities = { 75 | 0: uint ; psk-ease-of-input 76 | 1: [* psk-input-method] ; psk-input-methods 77 | 2: uint ; psk-min-bits-of-entropy 78 | } 79 | 80 | psk-input-method = &( 81 | numeric: 0 82 | qr-code: 1 83 | ) 84 | 85 | auth-initiation-token = { 86 | ? 0: text ; token 87 | } 88 | 89 | auth-spake2-psk-status = &( 90 | psk-needs-presentation: 0 91 | psk-shown: 1 92 | psk-input: 2 93 | ) 94 | 95 | ; type key 1003 96 | auth-spake2-confirmation = { 97 | 0: bytes .size 64 ; confirmation-value 98 | } 99 | 100 | auth-status-result = &( 101 | authenticated: 0 102 | unknown-error: 1 103 | timeout: 2 104 | secret-unknown: 3 105 | validation-took-too-long : 4 106 | proof-invalid: 5 107 | ) 108 | 109 | ; type key 1004 110 | auth-status = { 111 | 0: auth-status-result ; result 112 | } 113 | 114 | ; type key 1005 115 | auth-spake2-handshake = { 116 | 0: auth-initiation-token; initiation-token 117 | 1: auth-spake2-psk-status ; psk-status 118 | 2: bytes ; public-value 119 | } 120 | 121 | watch-id = uint 122 | 123 | ; type key 14 124 | presentation-url-availability-request = { 125 | request 126 | 1: [1* text] ; urls 127 | 2: microseconds ; watch-duration 128 | 3: watch-id ; watch-id 129 | } 130 | 131 | ; type key 15 132 | presentation-url-availability-response = { 133 | response 134 | 1: [1* url-availability] ; url-availabilities 135 | } 136 | 137 | ; type key 103 138 | presentation-url-availability-event = { 139 | 0: watch-id ; watch-id 140 | 1: [1* url-availability] ; url-availabilities 141 | } 142 | 143 | ; idea: use HTTP response codes? 144 | url-availability = &( 145 | available: 0 146 | unavailable: 1 147 | invalid: 10 148 | ) 149 | 150 | ; type key 104 151 | presentation-start-request = { 152 | request 153 | 1: text ; presentation-id 154 | 2: text ; url 155 | 3: [* http-header] ; headers 156 | } 157 | 158 | http-header = [ 159 | key: text 160 | value: text 161 | ] 162 | 163 | ; type key 105 164 | presentation-start-response = { 165 | response 166 | 1: &result ; result 167 | 2: uint ; connection-id 168 | ? 3: uint ; http-response-code 169 | } 170 | 171 | presentation-termination-source = &( 172 | controller: 1 173 | receiver: 2 174 | unknown: 255 175 | ) 176 | 177 | presentation-termination-reason = &( 178 | application-request: 1 179 | user-request: 2 180 | receiver-replaced-presentation: 20 181 | receiver-idle-too-long: 30 182 | receiver-attempted-to-navigate: 31 183 | receiver-powering-down: 100 184 | receiver-error: 101 185 | unknown: 255 186 | ) 187 | 188 | ; type key 106 189 | presentation-termination-request = { 190 | request 191 | 1: text ; presentation-id 192 | 2: presentation-termination-reason ; reason 193 | } 194 | 195 | ; type key 107 196 | presentation-termination-response = { 197 | response 198 | 1: &result ; result 199 | } 200 | 201 | ; type key 108 202 | presentation-termination-event = { 203 | 0: text ; presentation-id 204 | 1: presentation-termination-source ; source 205 | 2: presentation-termination-reason ; reason 206 | } 207 | 208 | ; type key 109 209 | presentation-connection-open-request = { 210 | request 211 | 1: text ; presentation-id 212 | 2: text ; url 213 | } 214 | 215 | ; type key 110 216 | presentation-connection-open-response = { 217 | response 218 | 1: &result ; result 219 | 2: uint ; connection-id 220 | 3: uint ; connection-count 221 | } 222 | 223 | ; type key 113 224 | presentation-connection-close-event = { 225 | 0: uint ; connection-id 226 | 1: &( 227 | close-method-called: 1 228 | connection-object-discarded: 10 229 | unrecoverable-error-while-sending-or-receiving-message: 100 230 | ) ; reason 231 | ? 2: text ; error-message 232 | 3: uint ; connection-count 233 | } 234 | 235 | ; type key 121 236 | presentation-change-event = { 237 | 0: text ; presentation-id 238 | 1: uint ; connection-count 239 | } 240 | 241 | ; type key 16 242 | presentation-connection-message = { 243 | 0: uint ; connection-id 244 | 1: bytes / text ; message 245 | } 246 | 247 | result = ( 248 | success: 1 249 | invalid-url: 10 250 | invalid-presentation-id: 11 251 | timeout: 100 252 | transient-error: 101 253 | permanent-error: 102 254 | terminating: 103 255 | unknown-error: 199 256 | ) 257 | 258 | ; type key 17 259 | remote-playback-availability-request = { 260 | request 261 | 1: [* remote-playback-source] ; sources 262 | 2: microseconds ; watch-duration 263 | 3: watch-id ; watch-id 264 | } 265 | 266 | ; type key 18 267 | remote-playback-availability-response = { 268 | response 269 | 1: [* url-availability] ; url-availabilities 270 | } 271 | 272 | ; type key 114 273 | remote-playback-availability-event = { 274 | 0: watch-id ; watch-id 275 | 1: [* url-availability] ; url-availabilities 276 | } 277 | 278 | ; type key 115 279 | remote-playback-start-request = { 280 | request 281 | 1: remote-playback-id ; remote-playback-id 282 | ? 2: [* remote-playback-source] ; sources 283 | ? 3: [* text] ; text-track-urls 284 | ? 4: [* http-header] ; headers 285 | ? 5: remote-playback-controls ; controls 286 | ? 6: {streaming-session-start-request-params} ; remoting 287 | } 288 | 289 | remote-playback-source = { 290 | 0: text; url 291 | 1: text; extended-mime-type 292 | } 293 | 294 | ; type key 116 295 | remote-playback-start-response = { 296 | response 297 | ? 1: remote-playback-state ; state 298 | ? 2: {streaming-session-start-response-params} ; remoting 299 | } 300 | 301 | ; type key 117 302 | remote-playback-termination-request = { 303 | request 304 | 1: remote-playback-id ; remote-playback-id 305 | 2: &( 306 | user-terminated-via-controller: 11 307 | unknown: 255 308 | ) ; reason 309 | } 310 | 311 | ; type key 118 312 | remote-playback-termination-response = { 313 | response 314 | 1: &result ; result 315 | } 316 | 317 | ; type key 119 318 | remote-playback-termination-event = { 319 | 0: remote-playback-id ; remote-playback-id 320 | 1: &( 321 | receiver-called-terminate: 1 322 | user-terminated-via-receiver: 2 323 | receiver-idle-too-long: 30 324 | receiver-powering-down: 100 325 | receiver-crashed: 101 326 | unknown: 255 327 | ) ; reason 328 | } 329 | 330 | ; type key 19 331 | remote-playback-modify-request = { 332 | request 333 | 1: remote-playback-id ; remote-playback-id 334 | 2: remote-playback-controls ; controls 335 | } 336 | 337 | ; type key 20 338 | remote-playback-modify-response = { 339 | response 340 | 1: &result ; result 341 | ? 2: remote-playback-state ; state 342 | } 343 | 344 | ; type key 21 345 | remote-playback-state-event = { 346 | 0: remote-playback-id ; remote-playback-id 347 | 1: remote-playback-state ; state 348 | } 349 | 350 | remote-playback-id = uint 351 | 352 | remote-playback-controls = { 353 | ? 0: remote-playback-source ; source 354 | ? 1: &( 355 | none: 0 356 | metadata: 1 357 | auto: 2 358 | ) ; preload 359 | ? 2: bool ; loop 360 | ? 3: bool ; paused 361 | ? 4: bool ; muted 362 | ? 5: float64 ; volume 363 | ? 6: media-timeline ; seek 364 | ? 7: media-timeline ; fast-seek 365 | ? 8: float64 ; playback-rate 366 | ? 9: text ; poster 367 | ? 10: [* text] ; enabled-audio-track-ids 368 | ? 11: text ; selected-video-track-id 369 | ? 12: [* added-text-track] ; added-text-tracks 370 | ? 13: [* changed-text-track] ; changed-text-tracks 371 | } 372 | 373 | remote-playback-state = { 374 | ? 0: { 375 | 0: bool ; rate 376 | 1: bool ; preload 377 | 2: bool ; poster 378 | 3: bool ; added-text-track 379 | 4: bool ; added-cues 380 | } ; supports 381 | ? 1: remote-playback-source ; source 382 | ? 2: &( 383 | empty: 0 384 | idle: 1 385 | loading: 2 386 | no-source: 3 387 | ) ; loading 388 | ? 3: &( 389 | nothing: 0 390 | metadata: 1 391 | current: 2 392 | future: 3 393 | enough: 4 394 | ) ; loaded 395 | ? 4: media-error ; error 396 | ? 5: epoch-time / null ; epoch 397 | ? 6: media-timeline / null ; duration 398 | ? 7: [* media-timeline-range] ; buffered-time-ranges 399 | ? 8: [* media-timeline-range] ; seekable-time-ranges 400 | ? 9: [* media-timeline-range] ; played-time-ranges 401 | ? 10: media-timeline ; position 402 | ? 11: float64 ; playbackRate 403 | ? 12: bool ; paused 404 | ? 13: bool ; seeking 405 | ? 14: bool ; stalled 406 | ? 15: bool ; ended 407 | ? 16: float64 ; volume 408 | ? 17: bool ; muted 409 | ? 18: video-resolution / null ; resolution 410 | ? 19: [* audio-track-state] ; audio-tracks 411 | ? 20: [* video-track-state] ; video-tracks 412 | ? 21: [* text-track-state] ; text-tracks 413 | } 414 | 415 | added-text-track = { 416 | 0: &( 417 | subtitles: 1 418 | captions: 2 419 | descriptions: 3 420 | chapters: 4 421 | metadata: 5 422 | ) ; kind 423 | ? 1: text ; label 424 | ? 2: text ; language 425 | } 426 | 427 | changed-text-track = { 428 | 0: text ; id 429 | 1: text-track-mode ; mode 430 | ? 2: [* text-track-cue] ; added-cues 431 | ? 3: [* text] ; removed-cue-ids 432 | } 433 | 434 | text-track-mode = &( 435 | disabled: 1 436 | showing: 2 437 | hidden: 3 438 | ) 439 | 440 | text-track-cue = { 441 | 0: text ; id 442 | 1: media-timeline-range ; range 443 | 2: text ; text 444 | } 445 | 446 | media-sync-time = [ 447 | value: uint 448 | scale: uint 449 | ] 450 | 451 | media-error = [ 452 | code: &( 453 | user-aborted: 1 454 | network-error: 2 455 | decode-error: 3 456 | source-not-supported: 4 457 | unknown-error: 5 458 | ) 459 | message: text 460 | ] 461 | 462 | track-state = ( 463 | 0: text ; id 464 | 1: text ; label 465 | 2: text ; language 466 | ) 467 | 468 | audio-track-state = { 469 | track-state 470 | 3: bool ; enabled 471 | } 472 | 473 | video-track-state = { 474 | track-state 475 | 3: bool ; selected 476 | } 477 | 478 | text-track-state = { 479 | track-state 480 | 3: text-track-mode ; mode 481 | } 482 | 483 | ; type key 22 484 | audio-frame = [ 485 | encoding-id: uint 486 | start-time: uint 487 | payload: bytes 488 | ? optional: { 489 | ? 0: uint ; duration 490 | ? 1: media-sync-time ; sync-time 491 | } 492 | ] 493 | 494 | ; type key 23 495 | video-frame = { 496 | 0: uint ; encoding-id 497 | 1: uint ; sequence-number 498 | ? 2: [* int] ; depends-on 499 | 3: uint ; start-time 500 | ? 4: uint ; duration 501 | 5: bytes ; payload 502 | ? 6: uint ; video-rotation 503 | ? 7: media-sync-time ; sync-time 504 | } 505 | 506 | ; type key 24 507 | data-frame = { 508 | 0: uint ; encoding-id 509 | ? 1: uint ; sequence-number 510 | ? 2: uint ; start-time 511 | ? 3: uint ; duration 512 | 4: bytes ; payload 513 | ? 5: media-sync-time ; sync-time 514 | } 515 | 516 | ratio = [ 517 | antecedent: uint 518 | consequent: uint 519 | ] 520 | 521 | ; type key 122 522 | streaming-capabilities-request = { 523 | request 524 | } 525 | 526 | ; type key 123 527 | streaming-capabilities-response = { 528 | response 529 | 1: streaming-capabilities ; streaming-capabilities 530 | } 531 | 532 | streaming-capabilities = { 533 | 0: [* receive-audio-capability] ; receive-audio 534 | 1: [* receive-video-capability] ; receive-video 535 | 2: [* receive-data-capability] ; receive-data 536 | } 537 | 538 | format = { 539 | 0: text ; codec-name 540 | } 541 | 542 | receive-audio-capability = { 543 | 0: format ; codec 544 | ? 1: uint ; max-audio-channels 545 | ? 2: uint ; min-bit-rate 546 | } 547 | 548 | video-resolution = { 549 | 0: uint ; height 550 | 1: uint ; width 551 | } 552 | 553 | video-hdr-format = { 554 | 0: text; transfer-function 555 | ? 1: text; hdr-metadata 556 | } 557 | 558 | receive-video-capability = { 559 | 0: format ; codec 560 | ? 1: video-resolution ; max-resolution 561 | ? 2: ratio ; max-frames-per-second 562 | ? 3: uint ; max-pixels-per-second 563 | ? 4: uint ; min-bit-rate 564 | ? 5: ratio ; aspect-ratio 565 | ? 6: text ; color-gamut 566 | ? 7: [* video-resolution] ; native-resolutions 567 | ? 8: bool ; supports-scaling 568 | ? 9: bool ; supports-rotation 569 | ? 10: [* video-hdr-format] ; hdr-formats 570 | } 571 | 572 | receive-data-capability = { 573 | 0: format ; data-type 574 | } 575 | 576 | ; type key 124 577 | streaming-session-start-request = { 578 | request 579 | streaming-session-start-request-params 580 | } 581 | 582 | ; type key 125 583 | streaming-session-start-response = { 584 | response 585 | streaming-session-start-response-params 586 | } 587 | 588 | ; A separate group so it can be used in remote-playback-start-request 589 | streaming-session-start-request-params = ( 590 | 1: uint ; streaming-session-id 591 | 2: [* media-stream-offer] ; stream-offers 592 | 3: microseconds ; desired-stats-interval 593 | ) 594 | 595 | ; type key 126 596 | streaming-session-modify-request = { 597 | request 598 | streaming-session-modify-request-params 599 | } 600 | 601 | ; A separate group so it can be used in remote-playback-start-response 602 | streaming-session-start-response-params = ( 603 | 1: &result ; result 604 | 2: [* media-stream-request] ; stream-requests 605 | 3: microseconds ; desired-stats-interval 606 | ) 607 | 608 | streaming-session-modify-request-params = ( 609 | 1: uint ; streaming-session-id 610 | 2: [* media-stream-request] ; stream-requests 611 | ) 612 | 613 | ; type key 127 614 | streaming-session-modify-response = { 615 | response 616 | 1: &result ; result 617 | } 618 | 619 | ; type key 128 620 | streaming-session-terminate-request = { 621 | request 622 | 1: uint ; streaming-session-id 623 | } 624 | 625 | ; type key 129 626 | streaming-session-terminate-response = { 627 | response 628 | } 629 | 630 | ; type key 130 631 | streaming-session-terminate-event = { 632 | 0: uint ; streaming-session-id 633 | } 634 | 635 | media-stream-offer = { 636 | 0: uint ; media-stream-id 637 | ? 1: text ; display-name 638 | ? 2: [1* audio-encoding-offer] ; audio 639 | ? 3: [1* video-encoding-offer] ; video 640 | ? 4: [1* data-encoding-offer] ; data 641 | } 642 | 643 | media-stream-request = { 644 | 0: uint ; media-stream-id 645 | ? 1: audio-encoding-request ; audio 646 | ? 2: video-encoding-request ; video 647 | ? 3: data-encoding-request ; data 648 | } 649 | 650 | audio-encoding-offer = { 651 | 0: uint ; encoding-id 652 | 1: text ; codec-name 653 | 2: uint ; time-scale 654 | ? 3: uint ; default-duration 655 | } 656 | 657 | video-encoding-offer = { 658 | 0: uint ; encoding-id 659 | 1: text ; codec-name 660 | 2: uint ; time-scale 661 | ? 3: uint ; default-duration 662 | ? 4: video-rotation ; default-rotation 663 | } 664 | 665 | data-encoding-offer = { 666 | 0: uint ; encoding-id 667 | 1: text ; data-type-name 668 | 2: uint ; time-scale 669 | ? 3: uint ; default-duration 670 | } 671 | 672 | audio-encoding-request = { 673 | 0: uint ; encoding-id 674 | } 675 | 676 | video-encoding-request = { 677 | 0: uint ; encoding-id 678 | ? 1: video-resolution ; target-resolution 679 | ? 2: ratio ; max-frames-per-second 680 | } 681 | 682 | data-encoding-request = { 683 | 0: uint ; encoding-id 684 | } 685 | 686 | video-rotation = &( 687 | ; Degrees clockwise 688 | video-rotation-0: 0 689 | video-rotation-90: 1 690 | video-rotation-180: 2 691 | video-rotation-270: 3 692 | ) 693 | 694 | sender-stats-audio = { 695 | 0: uint ; encoding-id 696 | ? 1: uint ; cumulative-sent-frames 697 | ? 2: microseconds ; cumulative-encode-delay 698 | } 699 | 700 | sender-stats-video = { 701 | 0: uint ; encoding-id 702 | ? 1: microseconds ; cumulative-sent-duration 703 | ? 2: microseconds ; cumulative-encode-delay 704 | ? 3: uint ; cumulative-dropped-frames 705 | } 706 | 707 | ; type key 131 708 | streaming-session-sender-stats-event = { 709 | 0: uint; streaming-session-id 710 | 1: microseconds ; system-time 711 | ? 2: [1* sender-stats-audio] ; audio 712 | ? 3: [1* sender-stats-video] ; video 713 | } 714 | 715 | streaming-buffer-status = &( 716 | enough-data: 0 717 | insufficient-data: 1 718 | too-much-data: 2 719 | ) 720 | 721 | receiver-stats-audio = { 722 | 0: uint ; encoding-id 723 | ? 1: microseconds ; cumulative-received-duration 724 | ? 2: microseconds ; cumulative-lost-duration 725 | ? 3: microseconds ; cumulative-buffer-delay 726 | ? 4: microseconds ; cumulative-decode-delay 727 | ? 5: streaming-buffer-status ; remote-buffer-status 728 | } 729 | 730 | receiver-stats-video = { 731 | 0: uint ; encoding-id 732 | ? 1: uint ; cumulative-decoded-frames 733 | ? 2: uint ; cumulative-lost-frames 734 | ? 3: microseconds ; cumulative-buffer-delay 735 | ? 4: microseconds ; cumulative-decode-delay 736 | ? 5: streaming-buffer-status ; remote-buffer-status 737 | } 738 | 739 | ; type key 132 740 | streaming-session-receiver-stats-event = { 741 | 0: uint; streaming-session-id 742 | 1: microseconds ; system-time 743 | ? 2: [1* receiver-stats-audio] ; audio 744 | ? 3: [1* receiver-stats-video] ; video 745 | } 746 | 747 | -------------------------------------------------------------------------------- /network_messages.cddl: -------------------------------------------------------------------------------- 1 | ; type key 1001 2 | auth-capabilities = { 3 | 0: uint ; psk-ease-of-input 4 | 1: [* psk-input-method] ; psk-input-methods 5 | 2: uint ; psk-min-bits-of-entropy 6 | } 7 | 8 | psk-input-method = &( 9 | numeric: 0 10 | qr-code: 1 11 | ) 12 | 13 | auth-initiation-token = { 14 | ? 0: text ; token 15 | } 16 | 17 | auth-spake2-psk-status = &( 18 | psk-needs-presentation: 0 19 | psk-shown: 1 20 | psk-input: 2 21 | ) 22 | 23 | ; type key 1003 24 | auth-spake2-confirmation = { 25 | 0: bytes .size 64 ; confirmation-value 26 | } 27 | 28 | auth-status-result = &( 29 | authenticated: 0 30 | unknown-error: 1 31 | timeout: 2 32 | secret-unknown: 3 33 | validation-took-too-long : 4 34 | proof-invalid: 5 35 | ) 36 | 37 | ; type key 1004 38 | auth-status = { 39 | 0: auth-status-result ; result 40 | } 41 | 42 | ; type key 1005 43 | auth-spake2-handshake = { 44 | 0: auth-initiation-token; initiation-token 45 | 1: auth-spake2-psk-status ; psk-status 46 | 2: bytes ; public-value 47 | } 48 | 49 | 50 | -------------------------------------------------------------------------------- /requirements.md: -------------------------------------------------------------------------------- 1 | # Requirements for Open Screen Protocol 2 | 3 | This document outlines functional and non-functional requirements of the Open 4 | Screen protocol. 5 | 6 | Functional requirements derive from the two Web APIs that the protocol will 7 | support: 8 | - The [Presentation API](https://w3c.github.io/presentation-api/) 9 | - The [Remote Playback API](https://w3c.github.io/remote-playback/) 10 | 11 | Non-functional requirements address efficiency, user experience, and security 12 | aspects of the protocols. 13 | 14 | ## Presentation API Requirements 15 | 16 | ### Terminology 17 | 18 | In [2-UA mode](https://w3c.github.io/presentation-api/#introduction), the 19 | Presentation API allows one browser (the 20 | [*controlling user agent*](https://w3c.github.io/presentation-api/#dfn-controlling-user-agent)) 21 | to discover and initiate presentation of Web content on a second user agent (the 22 | [*receiving user agent*](https://w3c.github.io/presentation-api/#receiving-user-agent), 23 | or *receiver*). We use the term 24 | [*presentation display*](https://w3c.github.io/presentation-api/#dfn-presentation-display) 25 | to refer to the entire device and software responsible for implementing the 26 | *receiver*, including browser, OS, networking and screen. 27 | 28 | A presentation is initiated at the request of a [*controlling browsing 29 | context*](https://w3c.github.io/presentation-api/#dfn-controlling-browsing-context) 30 | (or *controller*), which creates a [*receiving browsing 31 | context*](https://w3c.github.io/presentation-api/#dfn-receiving-browsing-context) 32 | (or *presentation*) to load a [*presentation request 33 | URL*](https://w3c.github.io/presentation-api/#dfn-presentation-url) and exchange 34 | messages with the resulting document. 35 | 36 | For detailed information about the behavior of the Presentation API operations 37 | described below, please consult the Presentation API specification. 38 | 39 | ### Presentation Display Availability 40 | 41 | 1. A controlling user agent must be able to discover the presence of a 42 | presentation display connected to the same IPv4 or IPv6 subnet and reachable 43 | by IP multicast. 44 | 45 | 2. A controlling user agent must be able to obtain the IPv4 or IPv6 address of 46 | the display, a friendly name for the display, and an IP port number for 47 | establishing a network transport to the display. 48 | 49 | 3. A controlling user agent must be able to determine if the receiver is 50 | reasonably capable of displaying a specific presentation request URL. 51 | 52 | ### Presentation Initiation 53 | 54 | 1. The controller must be able to start a new presentation on a receiver given a 55 | presentation request URL and presentation ID. 56 | 57 | ### Presentation Resumption 58 | 59 | 1. The controller must be able to reconnect to an active presentation on the 60 | receiver, given its presentation request URL and presentation ID. 61 | 62 | ### Presentation Connections 63 | 64 | 1. The controlling user agent or receiver must be able to close the connection 65 | between a controller and its presentation, and signal the other party with 66 | the reason why the connection was closed (`closed` or `wentaway`). 67 | 68 | 2. Multiple controllers must be able to connect to a presentation simultaneously 69 | (from one or more controlling user agents). 70 | 71 | ### Presentation Connection Messaging 72 | 73 | A *message* refers to the data passed with an invocation of 74 | `PresentationConnection.send()` by the controller or presentation. 75 | 76 | 1. Messages sent by the controller must be delivered to the presentation (or 77 | vice versa) in a reliable and in-order fashion. 78 | 79 | 2. If a message cannot be delivered, then the controlling user agent must be 80 | able to signal the receiver (or vice versa) that the connection should be 81 | closed with reason `error`. 82 | 83 | 3. The controller and presentation must be able to send and receive `DOMString` 84 | messages (represented as `string` type in ECMAScript). 85 | 86 | 4. The controller and presentation must be able to send and receive binary 87 | messages (represented as `Blob` objects in HTML5, or `ArrayBuffer` or 88 | `ArrayBufferView` types in ECMAScript). 89 | 90 | ### Presentation Termination 91 | 92 | 1. The controlling user agent must be able to signal to the receiver to 93 | terminate a presentation, given its presentation request URL and presentation 94 | ID. 95 | 96 | 2. The receiver must be able to signal all connected controlling user agents 97 | when a presentation is terminated. 98 | 99 | ## Remote Playback API Requirements 100 | 101 | TBD 102 | 103 | ## Non-functional Requirements 104 | 105 | ### Hardware and Efficiency 106 | 107 | 1. It should be possible to implement an Open Screen presentation display using 108 | modest hardware requirements, similar to what is found in a low end 109 | smartphone, smart TV or streaming device. See the [Device 110 | Specifications](device_specs.md) document for expected presentation display 111 | hardware specifications. 112 | 113 | 2. It should be possible to implement an Open Screen controlling user agent on a 114 | low-end smartphone. See the [Device Specifications](device_specs.md) document 115 | for expected controlling user agent hardware specifications. 116 | 117 | 3. The discovery and connection protocols should minimize power consumption, 118 | especially on the controlling user agent which is likely to be battery 119 | powered. 120 | 121 | ### Privacy and Security 122 | 123 | 1. The protocol should minimize the amount of information provided to a passive 124 | network observer about the identity of the user, activity on the controlling 125 | user agent and activity on the receiver. 126 | 127 | 2. The protocol should prevent passive network eavesdroppers from learning 128 | presentation URLs, presentation IDs, or the content of presentation messages 129 | passed between controllers and presentations. 130 | 131 | 3. The protocol should prevent active network attackers from impersonating a 132 | display and observing or altering data intended for the controller or 133 | presentation. 134 | 135 | ### User Experience 136 | 137 | 1. The controlling user agent should be able to discover quickly when a 138 | presentation display becomes available or unavailable (i.e., when it connects 139 | or disconnects from the network). 140 | 141 | 2. The controlling user agent should present sensible information to the user 142 | when a protocol operation fails. For example, if a controlling user agent is 143 | unable to start a presentation, it should be possible to report in the 144 | controlling user agent interface if it was a network error, authentication 145 | error, or the presentation content failed to load. 146 | 147 | 3. The controlling user agent should be able to remember authenticated 148 | presentation displays. This means it is not required for the user to 149 | intervene and re-authenticate each time the controlling user agent connects 150 | to a pre-authenticated display. 151 | 152 | 4. Message latency between the controller and a presentation should be minimized 153 | to permit interactive use. For example, it should be comfortable to type in 154 | a form in the controller and have the text appear in the presentation in real 155 | time. Real-time latency for gaming or mouse use is ideal, but not a 156 | requirement. 157 | 158 | 5. The controlling user agent initiating a presentation should communicate its 159 | preferred locale to the receiver, so it can render the presentation content 160 | in that locale. 161 | 162 | ### Extensibility 163 | 164 | 1. It should be possible to extend the control protocol (above the discovery and 165 | transport levels) with optional features not defined explicitly by the 166 | specification, to facilitate experimentation and enhancement of the base 167 | APIs. 168 | -------------------------------------------------------------------------------- /schemes.md: -------------------------------------------------------------------------------- 1 | # Schemes and Open Screen Protocol 2 | 3 | This document discusses the usage of HTTP schemes as a mechanism to make [Open 4 | Screen Protocol](https://webscreens.github.io/openscreenprotocol/) (OSP) agents 5 | extensible to support other kinds of applications in the future without the need 6 | for agreement between the agent implementations. 7 | 8 | The Presentation API allows a controller page to launch a presentation page on a 9 | display using the 10 | [`PresentationRequest`](https://www.w3.org/TR/presentation-api/#interface-presentationrequest) 11 | interface. The `PresentationRequest` constructor accepts a URL or a sequence of 12 | URLs of the presentation page as input. While the current Presentation API spec 13 | defines the behavior of `https` URLs, it does not forbid the usage of other URLs 14 | with other schemes. 15 | 16 | For example the `cast` scheme is used in the Presentation API tests as an 17 | alternative scheme to support [Google Cast](https://developers.google.com/cast/) 18 | receivers like Chromecast and Android TV. Let us consider the following example 19 | as input for discussion: 20 | 21 | ```javascript 22 | var urls = [ 23 | "hbbtv:?appId=123&orgId=456&appName=myHbbTVApp&appUrl=" + 24 | encodeURIComponent("https://example.com/hbbtv.html"), 25 | "https://example.com/presentation.html", 26 | "cast:1234567" 27 | ]; 28 | var request = new PresentationRequest(urls); 29 | ``` 30 | 31 | This example provides three URLs with different schemes: `hbbtv`, `https` and 32 | `cast`. The controlling UA that implements the OSP can use these schemes to 33 | filter presentation screens during discovery (regardless of which discovery 34 | protocol is used or how filtering is implemented). 35 | 36 | In order for a user to launch a presentation with a non-https URL scheme, they 37 | must have a presentation screen available that responds postively to screen 38 | availability requests for URLs with that scheme. 39 | 40 | If a single presentation screen supports more than one URL in a single 41 | `PresentationRequest,` the order of URLs is used by the controlling UA to decide 42 | which URL will be launched on that screen. This possibility is shown in the 43 | diagram below. If `Receiver Device 1` advertises itself as a single 44 | presentation screen, and the user chooses it as the target for `request`, then 45 | the controlling UA will launch the `hbbtv:` URL on it. 46 | 47 | ![](images/schemes.png) 48 | 49 | If the controlling page needs the user to choose which URL to present, it can 50 | create a separate `PresentationRequest` object for each URL. This is not 51 | recommended, as this would require the user to choose a connection technology 52 | (by virtue of calling `PresentationRequest.start()` on a URL-specific 53 | `PresentationRequest`). The user should generally not care about the details of 54 | the connection technology being used by the presentation screen. 55 | 56 | Alternatively, the presentation screen can advertise itself as multiple Open 57 | Screen Protocol endpoints, each of which advertises availability for a different 58 | scheme. In the case above, the user would see two distinct presentation screens 59 | in its screen list, "Receiver Device 1 (HBBTv)" and "Receiver Device 1 (Cast)". 60 | Again, this is not recommended as the user should not care about the connection 61 | technology used by a given screen. 62 | 63 | ## Extensibility 64 | 65 | The mechanism of using schemes in the OSP allows controlling pages to support 66 | additional receiver application types. For example, Android TV could implement 67 | the OSP receiver for native TV applications in the future and advertise them 68 | using the scheme `android.` A native Android TV app with a native library that 69 | acts as a presentation receiver could then be lauched and controlled by a 70 | controlling web page through the Presentation Controller API. 71 | 72 | Or, a controlling web page could open an HbbTV Web application on the OSP 73 | receiver with an `hbbtv:` URL. The page would use the `hbbtv` URL scheme to 74 | pass additional parameters that enable the receiving web page to access 75 | broadcast-specific functionality. 76 | 77 | ## Interoperability 78 | 79 | There remain interoperability concerns with supporting non-https schemes through 80 | the OSP. A browser may need to support additional features that are not part of 81 | the core OSP standard to work with a non-https application; this is true of 82 | `cast:` URLs today, for example. Browsers that do not have these features may 83 | believe that a non-https URL is available for presentation (because the 84 | receiving agent reports the URL as supported), but not be able to launch and 85 | control the presentation successfully via OSP. If [OSP 86 | extensions](https://webscreens.github.io/openscreenprotocol/#protocol-extensions) 87 | are required to control a non-https presentation, the non-https scheme may 88 | need to be mapped to an [OSP capability](https://github.com/webscreens/openscreenprotocol/blob/gh-pages/capabilities.md) so that agents can accurately determine compatbility. 89 | 90 | Another concern is the Web security model. Today, browsers decide which schemes 91 | should be considered secure from the controlling origin's point of view, and 92 | block URLs that do not meet those requirements. As OSP is intended to create a 93 | secure endpoint to the receiving agent, the expectation is that browsers should 94 | make an OSP-compliant endpoint accessible from secure contexts, even for 95 | presentations launched with non-https URLs. 96 | 97 | ## Scheme based filtering 98 | 99 | As discussed before, schemes can be used as a mechanism to filter devices during 100 | discovery. Two possible options: 101 | 102 | 1. The controlling UA sends the list requested schemes in the discovery request 103 | and receivers that support at least one scheme from the requested list should 104 | reply. Furthermore, discovery response of the receiver should include a 105 | sublist of supported schemes. 106 | 2. The controller UA don't send any scheme in the discovery request. The 107 | presentation screen should reply to any discovery request with a list of all 108 | supported schemes. The controlling UA matches the list of requested schemes 109 | with the list of supported schemes from each receiver to decide which device 110 | to consider. 111 | 112 | ## HbbTV scheme 113 | 114 | The example above shows the usage of `hbbtv` scheme. Basically, all required 115 | parameters to address an [HbbTV application](https://www.hbbtv.org/) on the terminal 116 | can be serialized as URL query parameters. The HbbTV URL in the example above 117 | contains the parameters `appId` (application ID) , `orgId` (organization ID), 118 | `appName` (application name) and `appUrl` (application URL), but other 119 | parameters can be supported in the same way. A receiver that advertises itself 120 | (e.g. `Receiver Device 1` depicted in the figure above) as a HbbTV terminal 121 | should use the scheme `hbbtv` during discovery. 122 | 123 | *TODO:* 124 | [Issue #94: Semantics of hbbtv: URLs](https://github.com/webscreens/openscreenprotocol/issues/94) 125 | 126 | -------------------------------------------------------------------------------- /scripts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c/openscreenprotocol/a438c32c21ee9998acb491af6194531cc6755a16/scripts/__init__.py -------------------------------------------------------------------------------- /scripts/cddl_lexer.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | from pygments.lexer import RegexLexer, bygroups, words 4 | from pygments.token import Text, Comment, Operator, Keyword, Name, String, \ 5 | Number, Punctuation 6 | 7 | # Based on draft spec here: 8 | # https://tools.ietf.org/html/draft-ietf-cbor-cddl-05#section-3 9 | 10 | 11 | class CustomLexer(RegexLexer): 12 | name = 'CDDL' 13 | aliases = ['cddl'] 14 | filenames = ['*.cddl'] 15 | 16 | flags = re.MULTILINE | re.UNICODE 17 | 18 | tokens = { 19 | 'root': [ 20 | (r'\n', Text), 21 | (r'\s+', Text), 22 | (r'\\\n', Text), # line continuations 23 | (r';[^\n]*\n', Comment.Single), 24 | 25 | (r'(true|false|null|nil)\b', Keyword.Constant), 26 | 27 | (words(( 28 | 'uint', 'nint', 'int', 29 | 'float16', 'float32', 'float64', 30 | 'bstr', 'tstr' 31 | ), suffix=r'\b(\()'), 32 | bygroups(Name.Builtin, Punctuation)), 33 | (words(( 34 | 'uint', 'nint', 'int', 35 | 'float16', 'float32', 'float64', 36 | 'bstr', 'tstr' 37 | ), suffix=r'\b'), 38 | Keyword.Type), 39 | 40 | # Representation type 41 | (r'#[0-7](\.\d+)?', Keyword.Type), 42 | 43 | # float_lit 44 | (r'\d+(\.\d+[eE][+\-]?\d+|' 45 | r'\.\d*|[eE][+\-]?\d+)', Number.Float), 46 | (r'\.\d+([eE][+\-]?\d+)?', Number.Float), 47 | 48 | # int_lit 49 | # -- octal_lit 50 | (r'0[0-7]+', Number.Oct), 51 | # -- hex_lit 52 | (r'0[xX][0-9a-fA-F]+', Number.Hex), 53 | # -- decimal_lit 54 | (r'(0|[1-9][0-9]*)', Number.Integer), 55 | 56 | # char_lit 57 | (r"""'(\\['"\\abfnrtv]|\\x[0-9a-fA-F]{2}|\\[0-7]{1,3}""" 58 | r"""|\\u[0-9a-fA-F]{4}|\\U[0-9a-fA-F]{8}|[^\\])'""", 59 | String.Char), 60 | 61 | # StringLiteral 62 | # -- raw_string_lit 63 | (r'`[^`]*`', String), 64 | # -- interpreted_string_lit 65 | (r'"(\\\\|\\"|[^"])*"', String), 66 | 67 | # Tokens 68 | (r'(<<=|>>=|<<|>>|<=|>=|&\^=|&\^|\+=|-=|\*=|/=|%=|&=|\|=|&&|\|\|' 69 | r'|<-|\+\+|--|==|!=|:=|\.\.\.|[+*/%&])', Operator), 70 | 71 | (r'[|^<>=!?()\[\]{}.,:]', Punctuation), 72 | 73 | # Outermost identifier 74 | (r'^[a-zA-Z0-9\-\_\@\.\$\s]+', Name.Class), 75 | 76 | # Nested identifier 77 | (r'[a-zA-Z0-9\-\_\@\.\$\s]+', Name.Other), 78 | ] 79 | } 80 | -------------------------------------------------------------------------------- /scripts/openscreen_cddl_dfns.py: -------------------------------------------------------------------------------- 1 | 2 | # This lists the CDDL types that are autolinked in the main Open Screen Protocol 3 | # specification. Only these types will be wrapped in tags and treated as 4 | # definitions. 5 | LINKED_TYPES = frozenset([ 6 | 'agent-info', 7 | 'agent-info-event', 8 | 'agent-info-request', 9 | 'agent-info-response', 10 | 'agent-status-request', 11 | 'agent-status-response', 12 | 'audio-encoding-offer', 13 | 'audio-frame', 14 | 'auth-capabilities', 15 | 'auth-initiation-token', 16 | 'auth-spake2-confirmation', 17 | 'auth-spake2-handshake', 18 | 'auth-spake2-need-psk', 19 | 'auth-status', 20 | 'data-encoding-offer', 21 | 'data-frame', 22 | 'media-time', 23 | 'presentation-change-event', 24 | 'presentation-connection-close-event', 25 | 'presentation-connection-message', 26 | 'presentation-connection-open-request', 27 | 'presentation-connection-open-response', 28 | 'presentation-start-request', 29 | 'presentation-start-response', 30 | 'presentation-termination-event', 31 | 'presentation-termination-request', 32 | 'presentation-termination-response', 33 | 'presentation-url-availability-event', 34 | 'presentation-url-availability-request', 35 | 'presentation-url-availability-response', 36 | 'remote-playback-availability-event', 37 | 'remote-playback-availability-request', 38 | 'remote-playback-availability-response', 39 | 'remote-playback-modify-request', 40 | 'remote-playback-modify-response', 41 | 'remote-playback-start-request', 42 | 'remote-playback-start-response', 43 | 'remote-playback-state-event', 44 | 'remote-playback-termination-event', 45 | 'remote-playback-termination-request', 46 | 'remote-playback-termination-response', 47 | 'streaming-capabilities-request', 48 | 'streaming-capabilities-response', 49 | 'streaming-session-modify-request', 50 | 'streaming-session-modify-response', 51 | 'streaming-session-receiver-stats-event', 52 | 'streaming-session-sender-stats-event', 53 | 'streaming-session-start-request', 54 | 'streaming-session-start-response', 55 | 'streaming-session-terminate-event', 56 | 'streaming-session-terminate-request', 57 | 'streaming-session-terminate-response', 58 | 'text-track-cue', 59 | 'video-encoding-offer', 60 | 'video-frame', 61 | 'video-request', 62 | ]) 63 | 64 | -------------------------------------------------------------------------------- /scripts/pygmentize_dir.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import re 5 | from glob import glob 6 | 7 | from pygments.formatters import HtmlFormatter 8 | from pygments import highlight 9 | 10 | from cddl_lexer import CustomLexer as CddlLexer 11 | import openscreen_cddl_dfns 12 | 13 | OUTPUT_EXTENSION = ".html" 14 | 15 | CDDL_TYPE_KEY_RE = re.compile(r'()([A-Za-z0-9-]+)'); 16 | 17 | class OSPHtmlFormatter(HtmlFormatter): 18 | def wrap(self, source): 19 | return self._wrap_code(source) 20 | 21 | def _wrap_code(self, source): 22 | yield 0, '
'
23 |     for i, t in source:
24 |       if i == 1:
25 |         m = CDDL_TYPE_KEY_RE.search(t)
26 |         if m and m.group(2) in openscreen_cddl_dfns.LINKED_TYPES:
27 |           t = CDDL_TYPE_KEY_RE.sub(r'\g<1>\g<2>', t)
28 |         yield 1, t
29 |     yield 0, '
' 30 | 31 | 32 | def pygmentize_file(lexer, formatter, filename): 33 | print("Reading file from: {}".format(filename)) 34 | with open(filename, 'r') as f: 35 | contents = f.read() 36 | 37 | return_val = highlight(contents, lexer, formatter) 38 | output_filename = "{}{}".format(os.path.splitext(filename)[0], 39 | OUTPUT_EXTENSION) 40 | 41 | with open(output_filename, 'w') as f: 42 | print("Pygmentizing output to: {}".format(output_filename)) 43 | f.write(return_val) 44 | 45 | 46 | def pygmentize_dir(lexer, formatter): 47 | for filename_match in lexer.filenames: 48 | for filename in glob(filename_match): 49 | pygmentize_file(lexer, formatter, filename) 50 | 51 | if __name__ == "__main__": 52 | formatter = OSPHtmlFormatter() 53 | 54 | directory, _ = os.path.split(os.path.abspath(__file__)) 55 | lexer = CddlLexer() 56 | 57 | pygmentize_dir(lexer, formatter) 58 | -------------------------------------------------------------------------------- /w3c.json: -------------------------------------------------------------------------------- 1 | { 2 | "group": [ 3 | "74168" 4 | ], 5 | "contacts": [ 6 | "tidoust" 7 | ], 8 | "repo-type": "rec-track" 9 | } --------------------------------------------------------------------------------