├── .github └── workflows │ ├── lint.yml │ └── render.yml ├── .gitignore ├── .lint ├── .gitignore ├── .init-scripts │ ├── make-build-tools.sh │ └── make-distclean.sh └── Makefile ├── .render ├── .gitignore ├── .init-scripts │ ├── make-build-tools.sh │ └── make-distclean.sh ├── Gemfile ├── Makefile ├── _config.yml ├── _local │ ├── _includes │ │ ├── apis_menu.html │ │ └── examples_menu.html │ └── assets │ │ └── css │ │ └── style.scss └── spec.json ├── APIs ├── ChannelMappingAPI.raml └── schemas │ ├── activation-response-schema.json │ ├── activation-schema.json │ ├── base-schema.json │ ├── error.json │ ├── input-base-schema.json │ ├── input-caps-response-schema.json │ ├── input-channels-response-schema.json │ ├── input-parent-response-schema.json │ ├── input-properties-schema.json │ ├── inputs-outputs-base-schema.json │ ├── io-response-schema.json │ ├── map-activations-activation-get-response-schema.json │ ├── map-activations-get-response-schema.json │ ├── map-activations-post-request-schema.json │ ├── map-activations-post-response-schema.json │ ├── map-active-output-response-schema.json │ ├── map-active-response-schema.json │ ├── map-base-schema.json │ ├── map-entries-schema.json │ ├── output-base-schema.json │ ├── output-caps-response-schema.json │ ├── output-channels-response-schema.json │ ├── output-properties-schema.json │ └── output-sourceid-response-schema.json ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── docs ├── APIs - Client Side Implementation.md ├── APIs - Server Side Implementation.md ├── APIs.md ├── Behaviour.md ├── Interoperability - NMOS IS-04.md ├── Interoperability.md ├── Overview.md ├── README.md ├── Upgrade Path.md └── images │ ├── map-examples.graffle │ ├── map-examples │ ├── input-constraints-block-crossover.png │ ├── input-constraints-block-input-gap.png │ ├── input-constraints-block-no-reordering.png │ ├── input-constraints-block-reordering.png │ ├── input-constraints-block-switching.png │ ├── input-constraints-crossover.png │ ├── input-constraints-gaps.png │ ├── input-constraints-input-gap.png │ ├── input-constraints-no-reordering.png │ ├── input-constraints-one-block.png │ ├── input-constraints-switching.png │ ├── re-entrant-example.png │ └── terminology.png │ ├── sequence-diagrams.graffle │ └── sequence-diagrams │ ├── receiver-sequence.png │ └── sender-sequence.png ├── examples ├── base-get-200.json ├── inputs │ ├── input-base-get-200.json │ ├── input-caps-get-200.json │ ├── input-channels-get-200.json │ ├── input-parent-get-200.json │ ├── input-properties-get-200.json │ └── inputs-base-get-200.json ├── io-get-200.json ├── map │ ├── map-activations-activation-get-200.json │ ├── map-activations-get-200.json │ ├── map-activations-post-200.json │ ├── map-activations-post-400.json │ ├── map-activations-post-423.json │ ├── map-activations-post.json │ ├── map-active-get-200.json │ ├── map-active-output-get-200.json │ └── map-base-get-200.json └── outputs │ ├── output-base-get-200.json │ ├── output-caps-get-200.json │ ├── output-channels-get-200.json │ ├── output-properties-get-200.json │ ├── output-sourceid-get-200.json │ └── outputs-base-get-200.json └── spec.yml /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | on: [push, pull_request, workflow_dispatch] 3 | jobs: 4 | lint: 5 | runs-on: ubuntu-latest 6 | name: Lint 7 | steps: 8 | - name: Use NMOS Lint 9 | uses: docker://amwa/nmos-lint:latest 10 | env: 11 | GITHUB_BRANCH: ${{ github.ref_name }} 12 | -------------------------------------------------------------------------------- /.github/workflows/render.yml: -------------------------------------------------------------------------------- 1 | name: Render 2 | on: 3 | workflow_dispatch: 4 | 5 | push: 6 | branches: 7 | - 'v[0-9]+.[0-9]+-dev' 8 | - 'v[0-9]+.[0-9]+.x' 9 | - 'publish-*' 10 | tags: 11 | - 'v[0-9]+.[0-9]+' 12 | - 'v[0-9]+.[0-9]+.[0-9]+' 13 | release: 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | name: Build 18 | steps: 19 | - name: Use NMOS Render 20 | uses: docker://amwa/nmos-render:latest 21 | env: 22 | SSH_HOST: ${{ secrets.SSH_HOST }} 23 | SSH_USER: ${{ secrets.SSH_USER }} 24 | SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} 25 | SSH_KNOWN_HOSTS: ${{ secrets.SSH_KNOWN_HOSTS }} 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *# 2 | *.swp 3 | *~ 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /.lint/.gitignore: -------------------------------------------------------------------------------- 1 | *# 2 | *.swp 3 | *~ 4 | .DS_Store 5 | .scripts/ 6 | node_modules/ 7 | npm-debug.log 8 | package-lock.json 9 | package.json 10 | yarn.lock 11 | -------------------------------------------------------------------------------- /.lint/.init-scripts/make-build-tools.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | 5 | git clone --single-branch --branch main https://${GITHUB_TOKEN:+${GITHUB_TOKEN}@}github.com/AMWA-TV/nmos-lint-scripts .scripts 6 | .scripts/install-dependencies.sh 7 | -------------------------------------------------------------------------------- /.lint/.init-scripts/make-distclean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | 5 | rm -rf package.json node_modules/ yarn.lock package-lock.json .scripts/ 6 | -------------------------------------------------------------------------------- /.lint/Makefile: -------------------------------------------------------------------------------- 1 | -include .scripts/scripts.mk 2 | 3 | .PHONY: build-tools distclean 4 | 5 | build-tools: 6 | .init-scripts/make-build-tools.sh 7 | 8 | distclean: 9 | .init-scripts/make-distclean.sh 10 | -------------------------------------------------------------------------------- /.render/.gitignore: -------------------------------------------------------------------------------- 1 | *# 2 | *.swp 3 | *~ 4 | .DS_Store 5 | .layouts/ 6 | .sass-cache/ 7 | .scripts/ 8 | Gemfile.lock 9 | /_layouts/ 10 | /_includes/ 11 | /assets/ 12 | /_data/ 13 | _site/ 14 | *.json 15 | branches/ 16 | index.md 17 | node_modules/ 18 | npm-debug.log 19 | package-lock.json 20 | package.json 21 | releases/ 22 | raml2html-nmos-theme/ 23 | source-repo/ 24 | yarn.lock 25 | -------------------------------------------------------------------------------- /.render/.init-scripts/make-build-tools.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | 5 | git clone --single-branch --branch "${NMOS_DOC_BUILD_SCRIPTS_BRANCH:-main}" https://${GITHUB_TOKEN:+${GITHUB_TOKEN}@}github.com/AMWA-TV/nmos-render-scripts .scripts 6 | .scripts/install-dependencies.sh 7 | -------------------------------------------------------------------------------- /.render/.init-scripts/make-distclean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o errexit 4 | 5 | rm -f index.md index-contents.md 6 | rm -rf source-repo/ branches/ releases/ 7 | rm -rf .scripts/ .layouts/ _layouts/ assets/ raml2html-nmos-theme/ _site/ .ssh/ 8 | rm -rf node_modules/ 9 | rm -f yarn.lock package.json package-lock.json Gemfile.lock 10 | -------------------------------------------------------------------------------- /.render/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gem 'github-pages', group: :jekyll_plugins 3 | gem 'faraday', '~>0' 4 | -------------------------------------------------------------------------------- /.render/Makefile: -------------------------------------------------------------------------------- 1 | -include .scripts/scripts.mk 2 | 3 | .PHONY: build-tools distclean 4 | 5 | build-tools: 6 | .init-scripts/make-build-tools.sh 7 | 8 | distclean: 9 | .init-scripts/make-distclean.sh 10 | -------------------------------------------------------------------------------- /.render/_config.yml: -------------------------------------------------------------------------------- 1 | # Don't change these 2 | theme: jekyll-theme-primer 3 | spec_server: specs.amwa.tv 4 | 5 | # AMWA ID 6 | amwa_id: IS-08 7 | 8 | # Base name for site (typically lower case version of AMWA ID, or the repo name) 9 | baseurl: /is-08 10 | 11 | # Which release or branch appears in header links and on the home page 12 | default_tree: releases/v1.0.1 # alternatively e.g. branches/v1.0.x 13 | 14 | # Regex patterns of releases and branches to show 15 | show_releases: ^v[0-9]+\.[0-9]+$|^v[0-9]+\.[0-9]+\.[0-9]+$ 16 | show_branches: ^v[0-9]+\.[0-9]+-dev$|^v[0-9]+\.[0-9]+\.x$|^publish- 17 | -------------------------------------------------------------------------------- /.render/_local/_includes/apis_menu.html: -------------------------------------------------------------------------------- 1 | APIS 2 | 12 | 13 | -------------------------------------------------------------------------------- /.render/_local/_includes/examples_menu.html: -------------------------------------------------------------------------------- 1 | EXAMPLES 2 | 8 | 9 | -------------------------------------------------------------------------------- /.render/_local/assets/css/style.scss: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | @import "{{ site.theme }}"; 5 | 6 | $dark: #418ab3; 7 | $mid_dark: #6faacb; 8 | $mid_light: #a5cadf; 9 | $light: #d1e4ef; 10 | 11 | body { 12 | margin: 0; 13 | background-color: white; 14 | font-family: Verdana, Geneva, Tahoma, sans-serif; 15 | } 16 | 17 | a { 18 | color: $dark; 19 | } 20 | 21 | h1 { 22 | color: $dark; 23 | text-align: center; 24 | } 25 | 26 | .markdown-body { 27 | font-family: Arial, Helvetica, sans-serif; 28 | } 29 | 30 | .markdown-body p { 31 | font-family: Verdana, Geneva, sans-serif; 32 | font-size: 100%; 33 | } 34 | 35 | .markdown-body h1 { 36 | font-size: 180%; 37 | } 38 | 39 | .markdown-body h2 { 40 | font-size: 150%; 41 | } 42 | 43 | .markdown-body h3 { 44 | font-size: 130%; 45 | } 46 | 47 | #logo-banner { 48 | display: table; 49 | width: 1024px; 50 | background-color: $dark; 51 | 52 | #nmos-logo { 53 | display: table-cell; 54 | width: 191px; 55 | height: 64px; 56 | margin: 10px; 57 | background-color: $dark; 58 | } 59 | 60 | #amwa-logo { 61 | display: table-cell; 62 | width: 191px; 63 | height: 64px; 64 | margin: 10px; 65 | background-color: $dark; 66 | } 67 | 68 | #title { 69 | display: table-cell; 70 | text-align: center; 71 | vertical-align: middle; 72 | font-size: 175%; 73 | padding-top: 10px; 74 | padding-bottom: 10px; 75 | color: $light; 76 | background-color: $dark; 77 | } 78 | 79 | #from-amwa-logo { 80 | display: table-cell; 81 | align-self: center; 82 | width: 243px; 83 | height: 64px; 84 | margin: 10px; 85 | background-color: $dark; 86 | } 87 | } 88 | 89 | .header { 90 | {% if site.amwa_id contains "IS-" or site.amwa_id contains "MS-" %} 91 | height: 88px; 92 | {% else %} 93 | height: 48px; 94 | {% endif %} 95 | line-height: 48px; 96 | width: 1024px; 97 | font-size: 100%; 98 | background: $mid_light; 99 | z-index: 1; 100 | 101 | a { 102 | display: inline-block; 103 | vertical-align: middle; 104 | line-height: normal; 105 | padding-left: 10px; 106 | padding-right: 10px; 107 | color: $dark; 108 | } 109 | 110 | .dropdown { 111 | display: inline-block; 112 | vertical-align: middle; 113 | line-height: normal; 114 | padding-left: 10px; 115 | padding-right: 10px; 116 | color: $dark; 117 | } 118 | 119 | .dropdown-content { 120 | display: none; 121 | position: absolute; 122 | background-color: $light; 123 | min-width: 100px; 124 | padding: 12px 16px; 125 | z-index: 7; 126 | font-size: 80%; 127 | } 128 | 129 | .dropdown:hover .dropdown-content { 130 | display: block; 131 | } 132 | 133 | 134 | 135 | .dropdown-3 { 136 | display: inline-block; 137 | vertical-align: middle; 138 | line-height: normal; 139 | padding-left: 10px; 140 | padding-right: 10px; 141 | color: $dark; 142 | } 143 | 144 | 145 | .dropdown-3-content { 146 | display: none; 147 | position: absolute; 148 | background-color: $light; 149 | min-width: 100px; 150 | padding: 12px 16px; 151 | z-index: 7; 152 | font-size: 80%; 153 | column-count: 3; 154 | max-height: 800px; 155 | } 156 | 157 | 158 | .dropdown-3:hover .dropdown-3-content { 159 | display: block; 160 | } 161 | 162 | .breadcrumbs { 163 | height: 40px; 164 | line-height: 40px; 165 | background: $light; 166 | 167 | a { 168 | color: $dark; 169 | } 170 | } 171 | 172 | .version-warning { 173 | background-color: #eea892; 174 | padding-left: 10px; 175 | padding-right: 10px; 176 | 177 | a { 178 | color: #df5327; 179 | } 180 | } 181 | 182 | } 183 | 184 | 185 | .content { 186 | padding: 16px; 187 | } 188 | 189 | .sticky { 190 | position: fixed; 191 | top: 0; 192 | width: 1024px; 193 | } 194 | 195 | .sticky + .content { 196 | padding-top: 102px; 197 | } 198 | 199 | html { 200 | scroll-padding-top: 100px; 201 | } 202 | -------------------------------------------------------------------------------- /.render/spec.json: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | {{ site.data.spec | jsonify }} 5 | -------------------------------------------------------------------------------- /APIs/ChannelMappingAPI.raml: -------------------------------------------------------------------------------- 1 | #%RAML 1.0 2 | 3 | # AMWA NMOS Audo Channel Mapping Specification: Channel Mapping API 4 | # (c) AMWA 2018 5 | 6 | title: Channel Mapping 7 | baseUri: http://api.example.com/x-nmos/channelmapping/{version} 8 | version: v1.0 9 | mediaType: application/json 10 | 11 | documentation: 12 | - title: Overview 13 | content: | 14 | The Channel Mapping API is exposed by NMOS Devices as a standard control interface for management of audio matrix mapping inside Devices. 15 | - title: Further Documentation 16 | content: | 17 | Further normative documentation covering the behaviour of this API is contained in the [docs](../docs) folder of this repository. 18 | /: 19 | displayName: Base 20 | get: 21 | description: List of paths available from this API 22 | responses: 23 | 200: 24 | body: 25 | example: !include ../examples/base-get-200.json 26 | type: !include schemas/base-schema.json 27 | /inputs: 28 | displayName: Inputs 29 | get: 30 | description: List all inputs available 31 | responses: 32 | 200: 33 | body: 34 | example: !include ../examples/inputs/inputs-base-get-200.json 35 | type: !include schemas/inputs-outputs-base-schema.json 36 | /{inputId}: 37 | uriParameters: 38 | inputId: 39 | type: string 40 | pattern: "^[a-zA-Z0-9\\-_]+$" 41 | get: 42 | description: List of paths available from this API endpoint 43 | responses: 44 | 200: 45 | body: 46 | example: !include ../examples/inputs/input-base-get-200.json 47 | type: !include schemas/input-base-schema.json 48 | 404: 49 | description: Returned when the requested resource does not exist 50 | /properties: 51 | displayName: Input Properties 52 | get: 53 | description: Get information about the specified Input, such as a human-readable name and description 54 | responses: 55 | 200: 56 | body: 57 | example: !include ../examples/inputs/input-properties-get-200.json 58 | type: !include schemas/input-properties-schema.json 59 | 404: 60 | description: Returned when the requested resource does not exist 61 | /parent: 62 | displayName: Input Parent 63 | get: 64 | description: Get information about the origin of the audio associated with the specified Input 65 | responses: 66 | 200: 67 | body: 68 | example: !include ../examples/inputs/input-parent-get-200.json 69 | type: !include schemas/input-parent-response-schema.json 70 | 404: 71 | description: Returned when the requested resource does not exist 72 | /channels: 73 | displayName: Input Channels 74 | get: 75 | description: Get information about the specified Input's channels, such as human-readable labels 76 | responses: 77 | 200: 78 | body: 79 | example: !include ../examples/inputs/input-channels-get-200.json 80 | type: !include schemas/input-channels-response-schema.json 81 | 404: 82 | description: Returned when the requested resource does not exist 83 | /caps: 84 | displayName: Input Capabilities 85 | get: 86 | description: Get information about the specified Input's capabilities, such as routing constraints 87 | responses: 88 | 200: 89 | body: 90 | example: !include ../examples/inputs/input-caps-get-200.json 91 | type: !include schemas/input-caps-response-schema.json 92 | 404: 93 | description: Returned when the requested resource does not exist 94 | /outputs: 95 | displayName: Outputs 96 | get: 97 | description: List all outputs available 98 | responses: 99 | 200: 100 | body: 101 | example: !include ../examples/outputs/outputs-base-get-200.json 102 | type: !include schemas/inputs-outputs-base-schema.json 103 | /{outputId}: 104 | uriParameters: 105 | outputId: 106 | type: string 107 | pattern: "^[a-zA-Z0-9\\-_]+$" 108 | get: 109 | description: List of paths available from this API endpoint 110 | responses: 111 | 200: 112 | body: 113 | example: !include ../examples/outputs/output-base-get-200.json 114 | type: !include schemas/output-base-schema.json 115 | 404: 116 | description: Returned when the requested resource does not exist 117 | /properties: 118 | displayName: Output Properties 119 | get: 120 | description: Get information about the specified Output, such as a human-readable name and description 121 | responses: 122 | 200: 123 | body: 124 | example: !include ../examples/outputs/output-properties-get-200.json 125 | type: !include schemas/output-properties-schema.json 126 | 404: 127 | description: Returned when the requested resource does not exist 128 | /sourceid: 129 | displayName: Output Source ID 130 | get: 131 | description: Get the ID of the Source associated with the specified Output 132 | responses: 133 | 200: 134 | body: 135 | example: !include ../examples/outputs/output-sourceid-get-200.json 136 | type: !include schemas/output-sourceid-response-schema.json 137 | 404: 138 | description: Returned when the requested resource does not exist 139 | /channels: 140 | displayName: Output Channels 141 | get: 142 | description: Get information about the specified Output's channels, such as human-readable labels 143 | responses: 144 | 200: 145 | body: 146 | example: !include ../examples/outputs/output-channels-get-200.json 147 | type: !include schemas/output-channels-response-schema.json 148 | 404: 149 | description: Returned when the requested resource does not exist 150 | /caps: 151 | displayName: Output Capabilities 152 | get: 153 | description: Get information about the specified Output's capabilities, such as routing constraints 154 | responses: 155 | 200: 156 | body: 157 | example: !include ../examples/outputs/output-caps-get-200.json 158 | type: !include schemas/output-caps-response-schema.json 159 | 404: 160 | description: Returned when the requested resource does not exist 161 | /map: 162 | displayName: Map 163 | get: 164 | description: List of paths available from this API endpoint 165 | responses: 166 | 200: 167 | body: 168 | example: !include ../examples/map/map-base-get-200.json 169 | type: !include schemas/map-base-schema.json 170 | /activations: 171 | displayName: Activations 172 | get: 173 | description: List pending scheduled activations 174 | responses: 175 | 200: 176 | body: 177 | example: !include ../examples/map/map-activations-get-200.json 178 | type: !include schemas/map-activations-get-response-schema.json 179 | post: 180 | description: Create a new activation 181 | body: 182 | type: !include schemas/map-activations-post-request-schema.json 183 | example: !include ../examples/map/map-activations-post.json 184 | responses: 185 | 200: 186 | description: > 187 | A 200 response is returned when a request for an immediate activation is accepted. 188 | body: 189 | type: !include schemas/map-activations-post-response-schema.json 190 | example: !include ../examples/map/map-activations-post-200.json 191 | 202: 192 | description: > 193 | A 202 response is returned when a request for a scheduled activation is accepted, to indicate 194 | that while the request itself was acceptable it has not yet been acted upon by the API. 195 | body: 196 | type: !include schemas/map-activations-post-response-schema.json 197 | example: !include ../examples/map/map-activations-post-200.json 198 | 400: 199 | description: > 200 | A 400 response is returned, for example, when the request did not meet the schema. 201 | body: 202 | type: !include schemas/error.json 203 | example: !include ../examples/map/map-activations-post-400.json 204 | 423: 205 | description: > 206 | A 423 response is returned when a conflicting activation has been scheduled. 207 | body: 208 | type: !include schemas/error.json 209 | example: !include ../examples/map/map-activations-post-423.json 210 | options: 211 | description: A pre-flight check generally used for Cross-Origin Resource Sharing (CORS) purposes 212 | responses: 213 | 200: 214 | 403: 215 | /{activationId}: 216 | uriParameters: 217 | activationId: 218 | type: string 219 | pattern: "^[a-zA-Z0-9\\-_]+$" 220 | get: 221 | description: Get a single pending scheduled activation 222 | responses: 223 | 200: 224 | body: 225 | example: !include ../examples/map/map-activations-activation-get-200.json 226 | type: !include schemas/map-activations-activation-get-response-schema.json 227 | 404: 228 | description: Could not find the requested resource 229 | delete: 230 | description: Cancel a pending scheduled activation 231 | responses: 232 | 204: 233 | description: Resource deleted successfully 234 | 404: 235 | description: Could not find the requested resource 236 | options: 237 | description: A pre-flight check generally used for Cross-Origin Resource Sharing (CORS) purposes 238 | responses: 239 | 200: 240 | 403: 241 | /active: 242 | displayName: Active Map 243 | get: 244 | description: Get a view of the entire active map 245 | responses: 246 | 200: 247 | body: 248 | example: !include ../examples/map/map-active-get-200.json 249 | type: !include schemas/map-active-response-schema.json 250 | /{outputId}: 251 | uriParameters: 252 | outputId: 253 | type: string 254 | pattern: "^[a-zA-Z0-9\\-_]+$" 255 | get: 256 | description: | 257 | Get the active map for the specified output. 258 | This resource allows a controller to fetch only the section of the map related to the specified output, without the need to fetch the entire map. 259 | responses: 260 | 200: 261 | body: 262 | example: !include ../examples/map/map-active-output-get-200.json 263 | type: !include schemas/map-active-output-response-schema.json 264 | 404: 265 | description: Returned when the requested resource does not exist 266 | /io: 267 | displayName: Inputs/Outputs View 268 | get: 269 | description: Get a view on all Inputs and Outputs 270 | responses: 271 | 200: 272 | body: 273 | example: !include ../examples/io-get-200.json 274 | type: !include schemas/io-response-schema.json 275 | -------------------------------------------------------------------------------- /APIs/schemas/activation-response-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "description": "Parameters concerned with activation of the channel mapping", 4 | "type": "object", 5 | "additionalProperties": false, 6 | "required": [ 7 | "mode", 8 | "requested_time", 9 | "activation_time" 10 | ], 11 | "properties": { 12 | "mode": { 13 | "description": "Mode of activation: immediate (on message receipt), scheduled_absolute (when internal clock >= requested_time), scheduled_relative (when internal clock >= time of message receipt + requested_time), or null (no activation scheduled).", 14 | "anyOf": [{ 15 | "type": "string", 16 | "enum": [ 17 | "activate_immediate", 18 | "activate_scheduled_absolute", 19 | "activate_scheduled_relative" 20 | ] 21 | }, { 22 | "type": "null" 23 | }] 24 | }, 25 | "requested_time": { 26 | "description": "String formatted TAI timestamp (:) indicating time (absolute or relative) for activation requested. For an immediate activation this field will always be null.", 27 | "anyOf": [{ 28 | "type": "string", 29 | "pattern": "^[0-9]+:[0-9]+$" 30 | }, { 31 | "type": "null" 32 | }] 33 | }, 34 | "activation_time": { 35 | "description": "String formatted TAI timestamp (:) indicating the absolute time the channel mapping will or did actually activate for scheduled activations, or the time activation occurred for immediate activations. For immediate activations this property will be the time the activation actually occurred in the response to the POST request.", 36 | "anyOf": [{ 37 | "type": "string", 38 | "pattern": "^[0-9]+:[0-9]+$" 39 | }, { 40 | "type": "null" 41 | }] 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /APIs/schemas/activation-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "object", 4 | "title": "Activation resource", 5 | "description": "Parameters concerned with activation of the channel mapping", 6 | "additionalProperties": false, 7 | "required": [ 8 | "mode" 9 | ], 10 | "properties": { 11 | "mode": { 12 | "description": "Mode of activation: immediate (on message receipt), scheduled_absolute (when internal clock >= requested_time), or scheduled_relative (when internal clock >= time of message receipt + requested_time)", 13 | "type": "string", 14 | "enum": [ 15 | "activate_immediate", 16 | "activate_scheduled_absolute", 17 | "activate_scheduled_relative" 18 | ] 19 | }, 20 | "requested_time": { 21 | "description": "String formatted TAI timestamp (:) indicating time (absolute or relative) for activation", 22 | "anyOf": [{ 23 | "type": "string", 24 | "pattern": "^[0-9]+:[0-9]+$" 25 | }, { 26 | "type": "null" 27 | }] 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /APIs/schemas/base-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "array", 4 | "description": "Describes the Channel Mapping API base resource", 5 | "title": "Channel Mapping API base resource", 6 | "items": { 7 | "type": "string", 8 | "enum": [ 9 | "inputs/", 10 | "outputs/", 11 | "map/", 12 | "io/" 13 | ] 14 | }, 15 | "minItems": 4, 16 | "maxItems": 4, 17 | "uniqueItems": true 18 | } 19 | -------------------------------------------------------------------------------- /APIs/schemas/error.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "object", 4 | "description": "Describes the standard error response which is returned with HTTP codes 400 and above", 5 | "title": "Error response", 6 | "required": [ 7 | "code", 8 | "error", 9 | "debug" 10 | ], 11 | "properties": { 12 | "code": { 13 | "description": "HTTP error code", 14 | "type": "integer", 15 | "minimum": 400, 16 | "maximum": 599 17 | }, 18 | "error": { 19 | "description": "Human readable message which is suitable for user interface display, and helpful to the user", 20 | "type": "string" 21 | }, 22 | "debug": { 23 | "description": "Debug information which may assist a programmer working with the API", 24 | "type": ["null", "string"] 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /APIs/schemas/input-base-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "array", 4 | "description": "Describes the Channel Mapping API input base resource", 5 | "title": "Channel Mapping API input base resource", 6 | "items": { 7 | "type": "string", 8 | "enum": [ 9 | "properties/", 10 | "parent/", 11 | "channels/", 12 | "caps/" 13 | ] 14 | }, 15 | "minItems": 4, 16 | "maxItems": 4, 17 | "uniqueItems": true 18 | } 19 | -------------------------------------------------------------------------------- /APIs/schemas/input-caps-response-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "object", 4 | "description": "Describes an input's capabilities", 5 | "title": "Input capabilities resource", 6 | "additionalProperties": false, 7 | "required":[ 8 | "reordering", 9 | "block_size" 10 | ], 11 | "properties":{ 12 | "reordering":{ 13 | "type": "boolean" 14 | }, 15 | "block_size":{ 16 | "type": "integer", 17 | "minimum": 1 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /APIs/schemas/input-channels-response-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "array", 4 | "description": "List of channels in an input", 5 | "title": "Input channel resource", 6 | "minItems": 1, 7 | "items": { 8 | "type": "object", 9 | "required": [ 10 | "label" 11 | ], 12 | "properties": { 13 | "label": { 14 | "type": "string" 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /APIs/schemas/input-parent-response-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "object", 4 | "additionalProperties": false, 5 | "description": "Gives details of where media connected to an Input came from", 6 | "title": "Input Parent Resource", 7 | "required":[ 8 | "id", 9 | "type" 10 | ], 11 | "properties": { 12 | "id":{ 13 | "type": [ 14 | "string", 15 | "null" 16 | ], 17 | "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" 18 | }, 19 | "type":{ 20 | "type": [ 21 | "string", 22 | "null" 23 | ], 24 | "enum":[ 25 | "source", 26 | "receiver", 27 | null 28 | ] 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /APIs/schemas/input-properties-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "object", 4 | "description": "Properties of the input", 5 | "title": "Input properties resource", 6 | "required":[ 7 | "name", 8 | "description" 9 | ], 10 | "properties": { 11 | "name":{ 12 | "type": "string", 13 | "description": "Human readable name for the input" 14 | }, 15 | "description":{ 16 | "type": "string", 17 | "description": "Human readable description of the input" 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /APIs/schemas/inputs-outputs-base-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "array", 4 | "description": "List of paths for the inputs or outputs", 5 | "title": "Inputs or Outputs base resource", 6 | "items": { 7 | "type": "string", 8 | "pattern": "^[a-zA-Z0-9\\-_]+/$" 9 | }, 10 | "uniqueItems": true 11 | } 12 | -------------------------------------------------------------------------------- /APIs/schemas/io-response-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "description": "IO Information view for entire API", 4 | "type": "object", 5 | "additionalProperties": false, 6 | "required": [ 7 | "inputs", 8 | "outputs" 9 | ], 10 | "properties": { 11 | "inputs":{ 12 | "type": "object", 13 | "patternProperties": { 14 | "^[a-zA-Z0-9\\-_]+$":{ 15 | "type": "object", 16 | "additionalProperties": false, 17 | "properties": { 18 | "properties":{ 19 | "$ref": "input-properties-schema.json" 20 | }, 21 | "parent":{ 22 | "$ref": "input-parent-response-schema.json" 23 | }, 24 | "channels":{ 25 | "$ref": "input-channels-response-schema.json" 26 | }, 27 | "caps":{ 28 | "$ref": "input-caps-response-schema.json" 29 | } 30 | } 31 | } 32 | } 33 | }, 34 | "outputs":{ 35 | "type": "object", 36 | "patternProperties": { 37 | "^[a-zA-Z0-9\\-_]+$":{ 38 | "type": "object", 39 | "additionalProperties": false, 40 | "properties": { 41 | "properties":{ 42 | "$ref": "output-properties-schema.json" 43 | }, 44 | "source_id":{ 45 | "$ref": "output-sourceid-response-schema.json" 46 | }, 47 | "channels":{ 48 | "$ref": "output-channels-response-schema.json" 49 | }, 50 | "caps":{ 51 | "$ref": "output-caps-response-schema.json" 52 | } 53 | } 54 | } 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /APIs/schemas/map-activations-activation-get-response-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "title": "Single activation endpoint", 4 | "description": "A single pending activation", 5 | "type": "object", 6 | "additionalPropertes": false, 7 | "required": [ 8 | "activation", 9 | "action" 10 | ], 11 | "properties": { 12 | "activation":{ 13 | "$ref": "activation-response-schema.json" 14 | }, 15 | "action:":{ 16 | "$ref": "map-entries-schema.json" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /APIs/schemas/map-activations-get-response-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "title": "Activations endpoint", 4 | "description": "List of all currently pending activations", 5 | "type": "object", 6 | "additionalPropertes": false, 7 | "patternProperties": { 8 | "^[a-zA-Z0-9\\-_]+$": { 9 | "type": "object", 10 | "additionalPropertes": false, 11 | "required": [ 12 | "activation", 13 | "action" 14 | ], 15 | "properties": { 16 | "activation":{ 17 | "$ref": "activation-response-schema.json" 18 | }, 19 | "action:":{ 20 | "$ref": "map-entries-schema.json" 21 | } 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /APIs/schemas/map-activations-post-request-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "title": "Activations endpoint", 4 | "description": "Add a new activation to the activations list", 5 | "type": "object", 6 | "additionalPropertes": false, 7 | "required": [ 8 | "activation", 9 | "action" 10 | ], 11 | "properties": { 12 | "activation":{ 13 | "$ref": "activation-schema.json" 14 | }, 15 | "action:":{ 16 | "$ref": "map-entries-schema.json" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /APIs/schemas/map-activations-post-response-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "title": "Activations endpoint", 4 | "description": "Activation response", 5 | "type": "object", 6 | "additionalPropertes": false, 7 | "maxProperties": 1, 8 | "patternProperties": { 9 | "^[a-zA-Z0-9\\-_]+$": { 10 | "type": "object", 11 | "additionalPropertes": false, 12 | "required": [ 13 | "activation", 14 | "action" 15 | ], 16 | "properties": { 17 | "activation":{ 18 | "$ref": "activation-response-schema.json" 19 | }, 20 | "action:":{ 21 | "$ref": "map-entries-schema.json" 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /APIs/schemas/map-active-output-response-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "object", 4 | "description": "Describes the map for one specific output", 5 | "title": "Map resource", 6 | "additionalProperties": false, 7 | "required": [ 8 | "map" 9 | ], 10 | "properties": { 11 | "activation": { 12 | "$ref": "activation-response-schema.json" 13 | }, 14 | "map":{ 15 | "allOf": [{ 16 | "$ref": "map-entries-schema.json" 17 | }, { 18 | "minProperties": 1, 19 | "maxProperties": 1 20 | }] 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /APIs/schemas/map-active-response-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "object", 4 | "description": "Describes the map for all outputs", 5 | "title": "Map resource", 6 | "additionalProperties": false, 7 | "required":[ 8 | "activation", 9 | "map" 10 | ], 11 | "properties": { 12 | "activation": { 13 | "$ref": "activation-response-schema.json" 14 | }, 15 | "map":{ 16 | "$ref": "map-entries-schema.json" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /APIs/schemas/map-base-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "array", 4 | "description": "Describes the Channel Mapping API map base resource", 5 | "title": "Channel Mapping API map base resource", 6 | "items": { 7 | "type": "string", 8 | "enum": [ 9 | "activations/", 10 | "active/" 11 | ] 12 | }, 13 | "minItems": 2, 14 | "maxItems": 2, 15 | "uniqueItems": true 16 | } 17 | -------------------------------------------------------------------------------- /APIs/schemas/map-entries-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "object", 4 | "description": "Describes the map table entries", 5 | "title": "Map table entries", 6 | "additionalProperties": false, 7 | "patternProperties": { 8 | "^[a-zA-Z0-9\\-_]+$": { 9 | "description": "Unique identifiers of the outputs", 10 | "patternProperties":{ 11 | "^(0|([1-9][0-9]*))$":{ 12 | "description": "Indexes of channels", 13 | "required":[ 14 | "input", 15 | "channel_index" 16 | ], 17 | "properties": { 18 | "input":{ 19 | "description": "Unique identifier of the input to which the channel to be routed belongs. null for unrouted.", 20 | "type": [ 21 | "string", 22 | "null" 23 | ] 24 | }, 25 | "channel_index":{ 26 | "description": "Index of the input channel to be routed. null for unrouted.", 27 | "type": [ 28 | "integer", 29 | "null" 30 | ] 31 | } 32 | } 33 | } 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /APIs/schemas/output-base-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "array", 4 | "description": "Describes the Channel Mapping API output base resource", 5 | "title": "Channel Mapping API output base resource", 6 | "items": { 7 | "type": "string", 8 | "enum": [ 9 | "properties/", 10 | "sourceid/", 11 | "channels/", 12 | "caps/" 13 | ] 14 | }, 15 | "minItems": 4, 16 | "maxItems": 4, 17 | "uniqueItems": true 18 | } 19 | -------------------------------------------------------------------------------- /APIs/schemas/output-caps-response-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "object", 4 | "description": "Describes an output's capabilities", 5 | "title": "Output capabilities resource", 6 | "required":[ 7 | "routable_inputs" 8 | ], 9 | "properties": { 10 | "routable_inputs":{ 11 | "description": "List of Inputs that may be routed to this Output, including null if unrouted Output channels are allowed. This property MUST be set to null, if no such restrictions exist.", 12 | "anyOf": [{ 13 | "type": "array", 14 | "items": { 15 | "type": [ 16 | "string", 17 | "null" 18 | ], 19 | "pattern": "^[a-zA-Z0-9\\-_]+$" 20 | }, 21 | "uniqueItems": true 22 | }, { 23 | "type": "null" 24 | }] 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /APIs/schemas/output-channels-response-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "array", 4 | "description": "List of channels in an output", 5 | "title": "Output channel resource", 6 | "minItems": 1, 7 | "items": { 8 | "type": "object", 9 | "required": [ 10 | "label" 11 | ], 12 | "properties": { 13 | "label": { 14 | "type": "string" 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /APIs/schemas/output-properties-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "object", 4 | "description": "Properties of the output", 5 | "title": "Output properties resource", 6 | "required":[ 7 | "name", 8 | "description" 9 | ], 10 | "properties": { 11 | "name":{ 12 | "type": "string", 13 | "description": "Human readable name for the output" 14 | }, 15 | "description":{ 16 | "type": "string", 17 | "description": "Human readable description of the output" 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /APIs/schemas/output-sourceid-response-schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": ["string", "null"], 4 | "description": "Gives an output's source ID", 5 | "title": "Output source ID resource", 6 | "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" 7 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | This document provides an overview of changes between released versions of this specification. It is particularly important to consider this when implementing APIs which may support multiple releases simultaneously to ease upgrades in large facilities (see [Upgrade Path](docs/Upgrade%20Path.md)). 4 | 5 | ## Release v1.0.1 (documentation clarifications and bug fixes only) 6 | 7 | * Resolve inconsistencies and references to earlier (pre-v1.0) behaviour. 8 | * More examples added and the diagrams updated for greater clarity. 9 | * Add 202 Accepted response in the RAML (was already in the text) for POST /map/activations 10 | * Remove unused 400 Bad Request response in the RAML for DELETE /map/activations/{activationId} 11 | * Narrow schema of activation requests to prevent requests which don't specify an activation 12 | * Widen pattern for API-assigned activation IDs to allow UUIDs 13 | * Widen schema for Output capabilities to allow routable_inputs to be `null` (was already in the text) 14 | 15 | ## Release v1.0 16 | 17 | * Initial release 18 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thanks for your interest in this AMWA NMOS Specification. 4 | 5 | AMWA Specifications (including Best Current Practices) are developed and ratified in accordance with 6 | AMWA's Specification Process. See BCP-001 on the [AMWA Specifications page](https://www.amwa.tv/specifications) 7 | 8 | They are created and updated in AMWA working groups, requiring AMWA membership for participation. 9 | 10 | AMWA member contributions to this Specification are made subject to AMWA's [IPR Policy](https://www.amwa.tv/about/policies/AMWA_IPR_Policy_V3.0.pdf). 11 | Contributions should be accompanied by the form in an appendix of that policy. 12 | 13 | For more information for those wishing to develop or contribute to AMWA NMOS Specifications, 14 | please see the NMOS [Wiki Page](https://github.com/amwa-tv/nmos/wiki/Maintainers) for maintainers. 15 | 16 | ## Reporting Issues 17 | 18 | AMWA members and non-members are welcome to raise issues via the GitHub Issues tab. 19 | 20 | ## Pull Requests 21 | 22 | We accept Pull Requests from AMWA members participating in relevant workgroups. These are subject to the IPR Policy. 23 | 24 | Please read about our [GitHub Workflow](https://github.com/amwa-tv/nmos/wiki/GitHub-Workflow) before creating a pull request, 25 | in particular the 'Maintaining a Specification' section, as we try to maintain a consistent approach to branches and releases. 26 | This should indicate which branch it is most appropriate to create your pull request against. 27 | 28 | Each NMOS workgroup has a number of members that will review a PR. 29 | 30 | ## Suggesting Improvements or Enhancements 31 | 32 | We are interested in hearing of suggestions, both for the spec itself and the accompanying documentation. 33 | Please use the issue tracker or [contact AMWA](https://www.amwa.tv/contact). 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2018 Advanced Media Workflow Association (AMWA) 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | THIS AMWA SPECIFICATION IS BEING OFFERED WITHOUT ANY WARRANTY WHATSOEVER, 2 | AND IN PARTICULAR, ANY WARRANTY OF NON-INFRINGEMENT IS EXPRESSLY DISCLAIMED. 3 | ANY USE OF THIS SPECIFICATION SHALL BE MADE ENTIRELY AT THE IMPLEMENTER'S 4 | OWN RISK, AND NEITHER AMWA, NOR ANY OF ITS MEMBERS OR CONTRIBUTORS, SHALL 5 | HAVE ANY LIABILITY WHATSOEVER TO ANY IMPLEMENTER OR THIRD PARTY FOR ANY 6 | DAMAGES OF ANY NATURE WHATSOEVER, DIRECTLY OR INDIRECTLY, ARISING FROM THE 7 | USE OF THIS SPECIFICATION. 8 | 9 | Readers are advised that any IPR contribution forms associated with this 10 | project are available from the [AMWA](http://amwa.tv/) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AMWA IS-08 NMOS Audio Channel Mapping Specification 2 | 3 | [![Lint Status](https://github.com/AMWA-TV/is-08/workflows/Lint/badge.svg)](https://github.com/AMWA-TV/is-08/actions?query=workflow%3ALint) 4 | [![Render Status](https://github.com/AMWA-TV/is-08/workflows/Render/badge.svg)](https://github.com/AMWA-TV/is-08/actions?query=workflow%3ARender) 5 | 6 | 7 | 8 | ### What does it do? 9 | 10 | - Allows channel-level operations within NMOS environments 11 | - For example: muting channels, swapping languages… 12 | 13 | ### Why does it matter? 14 | 15 | - Provides expected functionality for typical production/broadcast operations 16 | - Extends usefulness of IS-05 and other NMOS specs. 17 | 18 | ### How does it work? 19 | 20 | - Controller gets channel information from sending Node 21 | - …and sends mapping information to the receiving Node 22 | - Can also do sender-side mapping 23 | 24 | 25 | 26 | ## Getting started 27 | 28 | There is more information about the NMOS Specifications and their GitHub repos at . 29 | -------------------------------------------------------------------------------- /docs/APIs - Client Side Implementation.md: -------------------------------------------------------------------------------- 1 | # APIs: Client Side Implementation Notes 2 | 3 | _(c) AMWA 2018, CC Attribution-NoDerivatives 4.0 International (CC BY-ND 4.0)_ 4 | 5 | ## Failure Modes 6 | 7 | If a client receives a HTTP 500 response code from the API, a failure has occurred. The client should display the content of the response's `error` field to the user if possible, and indicate that the Device may be in a bad state. The client should also refresh the values in the `map/active` and `map/activations` endpoints to ensure it is accurately reflecting the current state of the API. 8 | -------------------------------------------------------------------------------- /docs/APIs - Server Side Implementation.md: -------------------------------------------------------------------------------- 1 | # APIs: Server Side Implementation Notes 2 | 3 | _(c) AMWA 2018, CC Attribution-NoDerivatives 4.0 International (CC BY-ND 4.0)_ 4 | 5 | ## Cross-Origin Resource Sharing (CORS) 6 | 7 | In order to permit web-based control interfaces to be hosted remotely, all NMOS APIs MUST implement valid CORS HTTP headers in responses to all requests. 8 | 9 | In addition to this, where highlighted in the API specifications servers MUST respond to HTTP pre-flight OPTIONS requests. Servers MAY additionally support HTTP OPTIONS requests made to any other API resource. 10 | 11 | In order to simplify development, the following headers may be returned in order to remove these restrictions as far as possible. Note that these are very relaxed and may not be suitable for a production deployment. 12 | 13 | ```http 14 | Access-Control-Allow-Origin: * 15 | Access-Control-Allow-Methods: GET, PUT, POST, PATCH, HEAD, OPTIONS, DELETE 16 | Access-Control-Allow-Headers: Content-Type, Accept 17 | Access-Control-Max-Age: 3600 18 | ``` 19 | 20 | To ensure compatibility, the response 'Access-Control-Allow-Headers' could be set from the request's 'Access-Control-Request-Headers'. 21 | -------------------------------------------------------------------------------- /docs/APIs.md: -------------------------------------------------------------------------------- 1 | # APIs 2 | {:.no_toc} 3 | 4 | * A markdown unordered list which will be replaced with the ToC, excluding the "Contents header" from above 5 | {:toc} 6 | 7 | _(c) AMWA 2016, CC Attribution-NoDerivatives 4.0 International (CC BY-ND 4.0)_ 8 | 9 | ## API Specifications 10 | 11 | The Channel Mapping API is specified using: 12 | 13 | * The following sub-sections describing common NMOS API properties. 14 | * [RAML](http://raml.org/) documents and [JSON schemas](http://tools.ietf.org/html/draft-zyp-json-schema-04) in the [APIs](../APIs/) folder. 15 | * Normative text in files in the [docs](../docs) directory. 16 | 17 | Examples of JSON format output are provided in the [examples](../examples/) folder. 18 | 19 | ## API Validation 20 | 21 | JSON schemas are included with the RAML API definitions. These include validation for values used within the APIs. It is strongly recommended that implementers of a Channel Mapping API use these JSON schemas as part of a validation stage when receiving interactions from clients. Invalid payloads should cause a 400 HTTP error (Bad Request) to be returned to the client. 22 | 23 | ### Content Types 24 | 25 | All APIs MUST provide a JSON representation signalled via 'Content-Type: application/json' headers. This SHOULD be the default content type in the absence of any requested alternative by clients. Other content types (such as HTML) are permitted if they are explicitly requested via Accept headers. 26 | 27 | ### API Paths 28 | 29 | All NMOS APIs MUST use a path in the following format. Other HTTP resources MAY be presented on the same port by the Node, provided all NMOS resources are available from the /x-nmos/ path as follows: 30 | 31 | ``` 32 | http(s)://:/x-nmos/// 33 | ``` 34 | 35 | At each level of the API from the base resource onwards, the response SHOULD include a JSON format array of the child resources available from that point. 36 | 37 | Nodes MAY extend the path for the Channel Mapping API with a suffix. For example, a Node implementation might choose to extend the path so that Devices on the Node have separate Channel Mapping API instances without having to use a different port for each Device's API. Such a path MUST be formatted as follows: 38 | 39 | ``` 40 | http(s)://:/x-nmos//// 41 | ``` 42 | 43 | The `` identifier MUST conform to the following regex pattern: 44 | 45 | ``` 46 | ^[a-zA-Z0-9\-_]+$ 47 | ``` 48 | 49 | This permits the use of a UUID, such as an associated IS-04 Device `id`, in the usual format or succinct local identifiers such as `slot2B`. 50 | 51 | ### Versioning 52 | 53 | All public APIs are versioned as follows: 54 | 55 | * Requesting the API base resource (such as http(s)://<ip address or hostname>:<port>/x-nmos/channelmapping/) will provide a list containing the versions of the API present on the node. 56 | * A versioned API response must include only resources which match the schema for that API version. 57 | * Data which is held for mismatched minor API versions may be returned if it can be conformed to the correct schema (see example below). Data must never be conformed between major API versions. 58 | 59 | #### Versioning Example 60 | 61 | A v1.1 API response may include: 62 | 63 | * v1.1 data without modification. 64 | * Data conforming to schemas less than v2.0 but greater than v1.1, with any non-v1.1 keys removed. 65 | 66 | ### Common API Base Resource 67 | 68 | ```json 69 | [ 70 | "v1.0/", 71 | "v2.0/", 72 | "v3.0/" 73 | ] 74 | ``` 75 | 76 | * Appending /v1.0/ to the API base resource will request version 1.0 of the API if available. 77 | * The versioning format is v<#MAJOR>.<#MINOR> 78 | * MINOR increments SHOULD be performed for non-breaking changes (such as the addition of attributes in a response) 79 | * MAJOR increments MUST be performed for breaking changes (such as the renaming of a resource or attribute) 80 | * Versions MUST be represented as complete strings. Parsing MUST proceed as follows: separate into two strings, using the point (.) as a delimiter. Compare integer representations of MAJOR, MINOR version (such that v1.12 is greater than v1.5). 81 | * Clients are responsible for identifying the correct API version they require. 82 | 83 | ### URLs: Approach to Trailing Slashes 84 | 85 | For consistency and in order to adhere to how these APIs are specified in RAML, the 'primary' path for every resource has the trailing slash omitted. 86 | 87 | In order to overcome shortcomings in some common libraries, the following requirements are imposed for the support of URL paths with or without trailing slashes. 88 | 89 | #### GET and HEAD Requests 90 | 91 | * Clients performing requests using these methods SHOULD correctly handle a 301 response (moved permanently). 92 | * When a 301 is supported, the client MUST follow the redirect in order to retrieve the required response payload. 93 | * Servers implementing the APIs MUST support requests using these methods to both the trailing slash and non-trailing slash path to each resource. One of these MAY produce a 301 response causing a redirect to the other if preferred. 94 | 95 | #### All Other Requests (PUT, POST, DELETE, OPTIONS etc) 96 | 97 | * Clients performing requests using these methods MUST use URLs with no trailing slash present. 98 | * Servers implementing the APIs MUST correctly interpret requests using these methods to paths without trailing slashes present. 99 | * Servers implementing the APIs MAY correctly interpret requests using these methods to paths with trailing slashes present for backward compatibility. 100 | * Servers SHOULD NOT respond with 3xx codes for these request types. 101 | 102 | ### Error Codes & Responses 103 | 104 | The NMOS APIs use HTTP status codes to indicate success, failure and other cases to clients as per [RFC 7231](https://tools.ietf.org/html/rfc7231) and related standards. Where the RAML specification of an API specifies explicit response codes it is expected that a client will handle these cases in a particular way. As explicit handling of every possible HTTP response code is not expected, clients must instead implement more generic handling for ranges of response codes (1xx, 2xx, 3xx, 4xx and 5xx). For HTTP codes 400 and upwards, a JSON format response MUST be returned as follows: 105 | 106 | #### Example Error Response 107 | 108 | ```json 109 | { 110 | "code": 400, 111 | "error": "Human readable message which is suitable for user interface display, and helpful to the user", 112 | "debug": "Programmer / debugging detail or traceback" 113 | } 114 | ``` 115 | 116 | In the above example, the 'code' should always match the HTTP status code. 'error' must always be present and in string format. 'debug' may be null if no further debug information is available. 117 | 118 | Further details on when APIs will respond with particular codes is covered in the [Behaviour](Behaviour.md) section. 119 | -------------------------------------------------------------------------------- /docs/Behaviour.md: -------------------------------------------------------------------------------- 1 | # Behaviour 2 | {:.no_toc} 3 | 4 | * A markdown unordered list which will be replaced with the ToC, excluding the "Contents header" from above 5 | {:toc} 6 | 7 | _(c) AMWA 2018, CC Attribution-NoDerivatives 4.0 International (CC BY-ND 4.0)_ 8 | 9 | ## Start-Up Behaviour 10 | 11 | This specification does not define the channel mapping behaviour at start-up, as this may depend on the nature of the Device the API is controlling. However, it is important that the channel mapping behaviour of the underlying Device is reflected in the API at start-up. 12 | 13 | ## Interaction with Other Protocols 14 | 15 | If the audio channel mapping behaviour of the Device is changed via another protocol or control interface the Device MUST update the information in the Channel Mapping API to accurately reflect the current behaviour of the Device. 16 | 17 | ## Inputs and Outputs 18 | 19 | The `inputs` and `outputs` resources enumerate the Inputs and Outputs respectively. Each Input and Output resource has a number of child resources. 20 | 21 | ### Identifiers 22 | 23 | Inputs and Outputs are represented by a unique identifier. This identifier MUST conform to the following regex pattern: 24 | 25 | ```regex 26 | ^[a-zA-Z0-9\-_]+$ 27 | ``` 28 | 29 | All Input and Output identifiers MUST be immutable. Two Inputs MUST NOT share an identifier. Two Outputs MUST NOT share an identifier. 30 | 31 | ### Properties 32 | 33 | Inputs and Outputs MUST also provide a human-readable name and description in the `properties` resource, intended to be exposed in control systems. 34 | 35 | These are distinct from the machine readable unique identifier. 36 | 37 | ### Output and Source Relationship 38 | 39 | The `sourceid` resource of an Output SHOULD be populated with a Source ID, if: 40 | 41 | * The output audio may be transmitted directly by an NMOS Sender belonging to the Device. 42 | 43 | * The output audio may be transformed by some process to create a new Source and/or Flow. 44 | 45 | * The Output is routed back to an Input of the Channel Mapping API (see [Re-entrant Mappings](#re-entrant-mappings)). 46 | 47 | Otherwise, the `sourceid` MAY be set to `null`. 48 | 49 | In the case where no audio is currently routed to an Output (i.e all its entries in the active map are `null`) then the Output still constitutes a Source, and as such the `sourceid` resource for the Output SHOULD still present a Source ID where it would otherwise be required to do so. 50 | 51 | ### Receiver / Source and Input Relationship 52 | 53 | Where the audio associated with a Channel Mapping API Input comes directly from an NMOS Receiver, then the `parent` resource of the Input is populated in one of two ways: 54 | 55 | * The ID of the originating Source SHOULD appear in the `id` field of the `parent` resource if this information is available via some in-stream or out-of-band method. 56 | 57 | * However, if information about the Source ID is not available, then the ID of the Receiver SHOULD appear in the `id` field of the `parent` resource. 58 | 59 | Where the received audio has undergone one or more Source-creating transformations between the Receiver and this Input, the `id` field of the `parent` resource SHOULD contain the ID of the immediate parent Source. 60 | 61 | On the other hand, if the Input does not have an associated NMOS Receiver or Source, the `id` field in the `parent` resource SHOULD be set to `null`. 62 | 63 | When the `id` contains a Source ID or Receiver ID, the `type` field MUST be populated with the string `source` or `receiver` as appropriate. 64 | When the `id` is `null`, the `type` field MUST also be populated with `null`. 65 | 66 | For example, the following are all valid: 67 | 68 | ```json 69 | { 70 | "id": "bdec047b-d161-492a-9496-96da704de2b1", 71 | "type": "source" 72 | } 73 | ``` 74 | 75 | ```json 76 | { 77 | "id": "a7250200-30ae-4866-9aeb-721f3f63f58d", 78 | "type": "receiver" 79 | } 80 | ``` 81 | 82 | ```json 83 | { 84 | "id": null, 85 | "type": null 86 | } 87 | ``` 88 | 89 | The `parent` resource MUST be populated as specified even when the Input is not currently receiving audio from the parent Receiver or Source. 90 | 91 | ### Channels 92 | 93 | Inputs and Outputs MUST have at least one channel listed in their `channels` resource. For some Devices the number of channels will be fixed - for example where an Input or Output represents a base-band connection to a Device such as analogue audio or AES3. 94 | 95 | Other Devices may be capable of dynamically creating or destroying channels, for example where the Input or Output represents an audio stream. The Channel Mapping API does not provide a mechanism for changing the number of channels in an Input or Output resource - this must be done through an out-of-band operation by the user or automatically by the Device. 96 | 97 | A change to the number of channels in an Input or Output MUST be represented in the Input's or Output's own `channels` resource, but also MUST be represented in the global `map/active` and `map/activations` resources - and in the global `io` resource. 98 | 99 | Newly created Output channels SHOULD start unrouted, with the `input` and `channel_index` properties for the channel in the map table being set to `null`. The decision as to which channels are deleted when the number of channels are removed is left as a decision to implementers, as it is likely to depend on the application of the Device. 100 | 101 | Where a channel is added to or removed from an Output this represents the creation of a new Source. 102 | 103 | ### Input Constraints 104 | 105 | Inputs may optionally constrain the way the channels contained in the Input may be routed, using the parameters exposed in the `caps` resource. 106 | 107 | If a client attempts to create a mapping that would violate these constraints the API SHOULD return an HTTP 400 response. This response SHOULD contain a message informing the client that the request was rejected because it did not respect an input constraint and also provide information about which constraint was broken, and for which channels and Inputs, in order to aid debugging. 108 | 109 | To illustrate Input constraints the following examples relate to mapping channels from 64-channel MADI ([Multichannel Audio Digital Interface, AES10](http://www.aes.org/publications/standards/search.cfm?docID=17)) Input onto a pair of 8-channel MADI Outputs. 110 | 111 | #### Re-ordering 112 | 113 | In some cases Inputs may not be capable of performing a re-ordering operation with their channels. In such cases the Channel Mapping API may be considered as a means of routing multiple channels of audio within a Device, rather than re-ordering channels, as in the following example: 114 | 115 | ![reordering constraint example](images/map-examples/input-constraints-no-reordering.png "Permissible Routing Without Re-ordering") 116 | 117 | If the Input is constrained in this way, i.e. it cannot perform re-ordering, the `reordering` parameter in the Input's `caps` resource MUST be set to `false`, and there MUST be a fixed offset for all Input and Output channel indexes in the mapping. 118 | 119 | For example, the following two mappings are only permissible if `reordering` is set to `true`: 120 | 121 | ![reordering constraint example](images/map-examples/input-constraints-gaps.png "Differing offsets are not permitted.") 122 | 123 | ![reordering constraint example](images/map-examples/input-constraints-switching.png "All channels must be consecutive.") 124 | 125 | However, the following two examples would be permissible if `reordering` is set to `false`, as the difference in offsets occurs across two different Outputs; 126 | the gap in the channels used from Input does not correspond to a gap within an Output. (However block constraints can make such an example not permitted – see below.) 127 | 128 | ![reordering constraint example](images/map-examples/input-constraints-input-gap.png "This constraint does not apply across different Outputs.") 129 | 130 | ![reordering constraint example](images/map-examples/input-constraints-crossover.png "Crossing Over is not permitted.") 131 | 132 | #### Channel Block Sizes 133 | 134 | Some Devices place a further constraint that channels must be treated as a discrete block from a given Input, where all channels in the block are expected to be routed together from a certain starting point, such that: 135 | 136 | * It MUST be that either all Input channels in a block are routed to an Output, or none are routed. 137 | * All Input channels in a block MUST be routed to the same Output when routed. 138 | * An Input channel MUST only be in one block. 139 | * All Input channels MUST be in a block. 140 | * All blocks MUST be the same size. 141 | * All blocks MUST start with an input channel where `channel_index` is zero or a multiple of the `block_size` parameter. 142 | 143 | Where an Input is constrained in this way the `block_size` parameter in the Input's `caps` resource MUST be an integer indicating the block size that is in use for that Input and the resulting Input Channel start. Otherwise the `block_size` parameter MUST be set to `1`. 144 | 145 | Consider a case where the specific architecture of a given MADI Card only allows processing of Input channels in blocks. The MADI channel numbers and corresponding Input `channel_index` values of these blocks are `0`-`7`, or `8`-`15`, or `16`-`23`, and so on. 146 | 147 | The following examples would be permissible, where a `block_size` value of `8` is used: 148 | 149 | ![block constraint example](images/map-examples/input-constraints-block-no-reordering.png "Permissible routing with blocks of 8") 150 | 151 | ![block constraint example](images/map-examples/input-constraints-block-crossover.png "Routing with blocks of 8 and crossover") 152 | 153 | The following examples would not be permissible: 154 | 155 | ![block constraint example](images/map-examples/input-constraints-block-input-gap.png "All of a block must be routed.") 156 | 157 | ![block constraint example](images/map-examples/input-constraints-block-reordering.png "Crossing Over within blocks is not permitted.") 158 | 159 | #### Combining Input Constraints 160 | 161 | The `block_size` and `reordering` parameters may both be used at the same time, to express a constraint where channels must be treated as blocks, and re-ordering in those blocks is not permitted. For example, the following would no longer be permitted when using a `block_size` of `8` when the `reordering` parameter is set to `false`: 162 | 163 | ![reordering constraint example](images/map-examples/input-constraints-block-switching.png "Re-ordering is allowed in blocks.") 164 | 165 | ### Output Routing Constraints 166 | 167 | It is recognised that not all Devices allow the routing of channels in any Input to any Output. In order to reflect this limitation, the Output `caps` resource presents a list of routable Inputs in the `routable_inputs` field. If such restrictions exist then they MUST be populated by the Device, such that if an Input is listed in an Output's routable input list then channels from that input can be routed to that Output in the Map table, and if the Device allows the Output to have unrouted channels, the list SHOULD also include `null`. If no such restrictions exist, the `routable_inputs` field MUST be set to `null`. 168 | 169 | Clients SHOULD NOT attempt to route channels from Inputs to an Output unless that Input is listed in the Output's `routable_inputs` array. If a client attempts to make such a route the API SHOULD respond with an HTTP 400 response. This error message SHOULD inform the client that it attempted to make an illegal route, and which inputs/outputs were involved in the illegal route. 170 | 171 | ## Map 172 | 173 | The `map` resource has child resources that represent the Active Map and any pending Activations. 174 | 175 | ### The Active Map 176 | 177 | The `active` resource contain a structure called `map`, which looks like the following: 178 | 179 | ```json 180 | "map":{ 181 | "outA":{ 182 | "0" :{ 183 | "input": "input1", 184 | "channel_index": 0 185 | }, 186 | "1":{ 187 | "input": "input1", 188 | "channel_index": 1 189 | } 190 | }, 191 | "outB":{ 192 | "0":{ 193 | "input": "input4", 194 | "channel_index": 0 195 | }, 196 | "1":{ 197 | "input": null, 198 | "channel_index": null 199 | } 200 | } 201 | } 202 | ``` 203 | 204 | The keys in the map object are the identifiers of all the Outputs in the API. Every Output has an object within the `map` object to represent it. Keys within an Output object represent channels in the Output, and are the JSON array index of the channel in the Output's `channels` resource. 205 | 206 | Each channel contains two fields - `input` and `channel_index`. `channel_index` is the JSON array index of the Input channel routed to that Output channel, as indicated by the Input's `channels` resource. `input` is the identifier of the Input to which the routed channel belongs. 207 | 208 | If no Input channel is being routed to an Output channel, both `input` and `channel_index` MUST be set to `null`. 209 | Where an Output does not have a channel routed to it the Device MUST interpret this as silence, and produce a silent signal of appropriate bit depth and bit rate from that output. 210 | 211 | ### Activation Requests 212 | 213 | Activations are the mechanism by which changes are made to the `active` resource. Activations can either be immediate or scheduled. 214 | In either case an activation is initiated by performing a POST request to the `activations` endpoint. 215 | 216 | When POSTing to the `activations` resource clients MUST use a subset of the map resource, such that only the entries to be updated are included. The API MUST leave values not expressly updated in the POST request unchanged by the activation. 217 | 218 | The submission of a scheduled activation MUST NOT result in any changes to the Device audio channel mapping behaviour until the activation time is reached. 219 | 220 | The client POST request contains `activation` and `active` objects that indicate when and what is to be changed respectively. 221 | The Device MUST undertake to apply the parameter changes to the underlying audio processing as close as possible to the time indicated by the `mode` property in the `activation` object, as follows: 222 | 223 | - `activate_immediate` - on message receipt 224 | - `activate_scheduled_absolute` - the absolute time indicated by the `requested_time` field 225 | - `activate_scheduled_relative` - the relative time after message receipt indicated by the `requested_time` field 226 | 227 | See the [Timestamps](#Timestamps) section for more details on the required interpretation of the timestamps for scheduled activations. 228 | 229 | Once an activation has been completed the resulting changes to the map MUST be reflected in the `active` endpoint. The `activation` object in the `active` endpoint MUST contain the details of the last activation to have taken place. 230 | 231 | #### Activation Responses 232 | 233 | Each successful activation request is allocated a unique identifier by the API. This identifier MUST be unique within an API instance and for all time. 234 | 235 | Pending scheduled activations, along with their ID, are listed in the `activations` resource until they activate. Once activated they MUST be removed from the resource. Immediate activations MUST NOT appear in the `activations` list, as they are carried out upon arrival. 236 | 237 | The unique identifier is returned as part of the activation response, to allow the client to cancel scheduled activations if required. 238 | 239 | Note the presence of the extra `activation_time` parameter in the response schema. For immediate activation this SHOULD be the time the activation actually occurred as an absolute TAI timestamp. 240 | 241 | An HTTP 200 response MUST be returned when an immediate activation has been successfully requested. For a request with an immediate activation the API SHOULD only return a response once the new map has been applied to the audio. 242 | 243 | An HTTP 202 response MUST be returned when a request for a scheduled activation is accepted, to indicate that while the request itself was acceptable it has not yet been acted upon by the device. For scheduled activations `activation_time` SHOULD be the absolute TAI time the parameters will actually transition. For absolute scheduled activations, it SHOULD be the same as the requested time, but may differ if the Device is unable to schedule at the requested time. 244 | 245 | When there is an error in the request, the API MUST reject the entire request with an appropriate 4xx response. Particular responses MUST be used in the following cases: 246 | 247 | | Error | HTTP Response | 248 | | --- | --- | 249 | | Output is modified by an already scheduled activation. | 423 (Locked) | 250 | | Routing request not permitted by Input or Output constraints. | 400 (Bad Request) | 251 | | One field of Output channel object is `null` but other is not. | 400 (Bad Request) | 252 | 253 | #### Canceling Activations 254 | 255 | A client cancels an activation by submitting a DELETE request to the resource `/map/activations/{activationId}`. If the activation has already been completed the API MUST respond with an HTTP 404 error response, as the activation no longer exists. 256 | 257 | ### Timestamps 258 | 259 | Timestamps indicate the absolute or relative time for activation and MUST be string formatted as `:`. Absolute timestamps MUST be based on TAI (which does not apply leap seconds) and must use SMPTE epoch (meaning 1970-01-01 00:00:00 TAI would be represented as `0:0`). 260 | 261 | Devices receiving their time references in UTC MUST maintain an up-to-date knowledge of when leap seconds will be applied in order to correctly calculate TAI time. Leap seconds are announced by the [International Earth Rotation and Reference System Service (IERS)](https://www.iers.org/SharedDocs/News/EN/BulletinC.html) and the IETF publish an [adjustment table](https://www.ietf.org/timezones/data/leap-seconds.list). 262 | 263 | ### Re-entrant Mappings 264 | 265 | Some Devices have more complex routing requirements. For example, a Device may have a large number of channels on an input, but restrictions in DSP capacity may mean that only a limited sub-set of these channels can be routed at any given time. For example, the Device illustrated below has a 64 channel MADI Input, but a limited number of MADI cards, meaning it can only process 16 of the 64 channels at any one time. Any of the outputs of the MADI cards can then be routed to a two channel AES67 output. 266 | 267 | ![re-entrant mapping example](images/map-examples/re-entrant-example.png "Re-entrant mapping example") 268 | 269 | In this example we indicate which inputs can be routed to the AES67 output with `/outputs/aes67/caps` as follows: 270 | ```json 271 | { 272 | "routable_inputs": [ 273 | "madi-a", 274 | "madi-b" 275 | ] 276 | } 277 | ``` 278 | 279 | And the re-entrant mapping is represented with `/map/active/aes67`: 280 | ```json 281 | { 282 | "aes67":{ 283 | "0":{ 284 | "input": "madi-b", 285 | "channel_index": 0 286 | }, 287 | "1":{ 288 | "input": "madi-b", 289 | "channel_index": 2 290 | } 291 | } 292 | } 293 | ``` 294 | 295 | In this scenario the audio undergoes two distinct routing operations - the first from the MADI input to the MADI card, and then a second from the MADI card to the AES67 output. In order to allow for these kinds of restrictions the Channel Mapping API supports re-entrant mappings, in which audio at an Output may be routed back to an Input. This is signaled to the control system by the same Source ID being present in both the Output's `sourceid` resource and also the Input's `parent` resource. 296 | 297 | Where this is done, Output constraints MUST prevent audio being routed back to the Output from which it originated. 298 | 299 | ## Inputs/Outputs View 300 | 301 | The `io` resource provides a single response detailing all Inputs, Outputs and available mappings between them. 302 | 303 | The object returned from this resource contains an `inputs` object and an `outputs` object. These two objects contain objects representing each of the Inputs and Outputs. Each Input and Output object MUST contain properties corresponding to the child resources described in [Inputs and Outputs](#inputs-and-outputs), with matching values. 304 | -------------------------------------------------------------------------------- /docs/Interoperability - NMOS IS-04.md: -------------------------------------------------------------------------------- 1 | # Interoperability: NMOS IS-04 2 | {:.no_toc} 3 | 4 | * A markdown unordered list which will be replaced with the ToC, excluding the "Contents header" from above 5 | {:toc} 6 | 7 | _(c) AMWA 2018, CC Attribution-NoDerivatives 4.0 International (CC BY-ND 4.0)_ 8 | 9 | The Audio Channel Mapping Specification shares a data model with the NMOS IS-04 specification, and as a result it is designed to be used alongside it. The following implementation notes identify correct behavior for doing this. 10 | 11 | When this API is used alongside IS-04 in a deployment, the IS-04 APIs should be operating at version 1.1 or greater in order to ensure full interoperability. 12 | 13 | ## Discovery 14 | 15 | The Channel Mapping API should be advertised as a 'control' endpoint when publishing a compliant NMOS Device. By using the common type 'urn:x-nmos:control:cm-ctrl/v1.0', control interfaces can identify all Devices which implement the Channel Mapping API, and the URLs required to access them. For more details see [NMOS Device Control Types](https://github.com/AMWA-TV/nmos-parameter-registers/tree/master/device-control-types). 16 | 17 | **Example 1:** The 'controls' attribute of the NMOS Device of a simple Node with a single device and Channel Mapping API instance 18 | 19 | ```json 20 | ... 21 | "controls": [ 22 | { 23 | "type": "urn:x-nmos:control:cm-ctrl/v1.0", 24 | "href": "http://192.168.10.3/x-nmos/channelmapping/v1.0/" 25 | } 26 | ] 27 | ... 28 | ``` 29 | 30 | **Example 2:** The 'controls' attribute of an NMOS Device of a Node which advertises a different Channel Mapping API instance for each device 31 | 32 | ```json 33 | ... 34 | "controls": [ 35 | { 36 | "type": "urn:x-nmos:control:cm-ctrl/v1.0", 37 | "href": "http://192.168.10.3/x-nmos/channelmapping/v1.0/slot2B/" 38 | } 39 | ] 40 | ... 41 | ``` 42 | 43 | The path segment 'slot2B' is the `` identifier, defined in [API Paths](APIs.md#api-paths). 44 | This permits the use of a UUID, such as an associated IS-04 Device `id`, in the usual format or succinct local identifiers such as `slot2B`. 45 | Human-readable information can be provided, for example, via the IS-04 Device `label` and `description`. 46 | 47 | Note as above that the API version is included in the 'type', and in the 'href'. As new versions of the Channel Mapping API are published, further control endpoints may be advertised for Devices which support multiple versions simultaneously. 48 | 49 | More details about multi-version support can be found in [Upgrade Path](Upgrade%20Path.md). 50 | 51 | A given instance of the Channel Mapping API MAY offer control of multiple Devices in a Node from a single URI. Alternatively there MAY be multiple instances of the API on one Node, for example, each corresponding to one Device. In either case, the 'control' endpoint for each Device's Channel Mapping API instance MUST be advertised, even if the URI is the same. 52 | 53 | This flexibility is to accommodate different relationships between Devices and Nodes. For example, some Devices may be loosely coupled to the Node, for example cards in a card frame. These Devices are more likely to have an instance of the API for each card. Others may be tightly coupled, for example a media processing pipeline on a server, where it is likely to be preferable to have one instance of the API that is advertised for each pipeline. 54 | 55 | ## Receiver and Source IDs 56 | 57 | The Source and Receiver UUIDs used in the API to identify relationships to Inputs and Outputs MUST match those used in a corresponding IS-04 implementation. 58 | 59 | Where this Device creates a new Source at an Output (see [Behaviour](Behaviour.md)), the Device MUST advertise these in the IS-04 Node API, and in the IS-04 registry if available. 60 | 61 | ## Version Increments 62 | 63 | In order to prevent unnecessary polling of the Channel Mapping API active map resource, any changes to active map parameters belonging to Source connected Outputs MUST be signaled via the IS-04 versioning mechanism by means of a version timestamp increment on the related "source" object. 64 | 65 | In all cases: 66 | 67 | - Device version number SHOULD increment if the map has been modified. 68 | - Source version number SHOULD increment if the output that has been modified is a parent of a registered Source. 69 | -------------------------------------------------------------------------------- /docs/Interoperability.md: -------------------------------------------------------------------------------- 1 | # Interoperability 2 | 3 | _(c) AMWA 2018, CC Attribution-NoDerivatives 4.0 International (CC BY-ND 4.0)_ 4 | 5 | The Audio Channel Mapping Specification is intended to be used alongside other NMOS specifications, and may also be used alongside other common non-NMOS specifications. These documents cover common interoperability requirements when operating in such situations. 6 | -------------------------------------------------------------------------------- /docs/Overview.md: -------------------------------------------------------------------------------- 1 | # AMWA NMOS Audio Channel Mapping Specification: Overview 2 | {:.no_toc} 3 | 4 | * A markdown unordered list which will be replaced with the ToC, excluding the "Contents header" from above 5 | {:toc} 6 | 7 | _(c) AMWA 2018, CC Attribution-NoDerivatives 4.0 International (CC BY-ND 4.0)_ 8 | 9 | ## Documentation 10 | 11 | The documents included in this directory provide additional details and recommendations for implementations of the defined API, and its consumers. 12 | 13 | ## Introduction 14 | 15 | The purpose of this document is to explain how an NMOS compatible system can re-map audio channels. This can take place on a sending device, where the resulting re-mapped audio may be sent out over the network, or a receiving device, where audio received from the network may be re-mapped prior to consumption. 16 | 17 | The terms 'Node', 'Device', 'Sender' and 'Receiver' will be used extensively throughout this document. Please refer to the core [NMOS Technical Overview](https://github.com/AMWA-TV/nmos/blob/master/NMOS%20Technical%20Overview.md) for definitions of these. 18 | 19 | This API is intended to be used in conjunction with an [IS-04 NMOS Discovery and Registration](https://github.com/AMWA-TV/nmos-discovery-registration) deployment, however it has been written in such a way to provide useful functionality even in the absence of such a system. 20 | 21 | This API may also be used on a Device that supports [IS-05 NMOS Device Connection Management](https://github.com/AMWA-TV/nmos-device-connection-management), but still provides useful functionality when used on Devices where connections are established by other means. 22 | 23 | ## Use of Normative Language 24 | The documents included in this Directory form a normative part of the specification, along with the API definitions and schemas included in the [APIs directory](../APIs). 25 | 26 | The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://tools.ietf.org/html/rfc2119). 27 | 28 | ## Terminology 29 | 30 | The API may be used to define a mapping between one or more audio "Inputs" and one or more audio "Outputs". Inputs and Outputs are resources local to the device, and as such are not published to the registry. An Input can be assigned audio from an NMOS Receiver, or can represent audio sources from elsewhere (e.g a microphone or physical input). Similarly audio routed to an Output can be assigned to an NMOS Source, or can be consumed elsewhere (e.g be routed to a loudspeaker or a physical output). A Device may also wish to direct audio from an Output back into a Device's Input, as a way of expressing complex Device routing limitations. 31 | 32 | A Device may not be able to arbitrarily route audio from any Input to any Output. As such the API allows the Device it is running on to express these limitations. 33 | 34 | Inputs and Outputs both have a number of Channels available for use. An Input represents each of the audio tracks assigned to it as a Channel. The number of channels an Input or Output has can be restricted by the Device, and cannot be altered by the client. 35 | 36 | The relationship between Input channels and Output channels is defined by the "Map". Where a given Input is routable to a given Output, it MUST be possible to route any of the Input's channels to any channel of the Output. An Output channel that does not have an Input channel routed to it is said to be "unrouted" (sometimes known as "parked"). 37 | 38 | The following shows an example of an IS-08 Map between two eight-channel Inputs and two eight-channel Outputs, represented as a logical wiring diagram and as a routing matrix: 39 | 40 | ![terminology example](images/map-examples/terminology.png "Terminology example") 41 | 42 | Note that: 43 | 44 | - The eight Output A channels are routed as a block to the eight Input A channels. This could be due to hardware limitations on those channels, which can be signalled as a constraint in IS-08 (see below). 45 | - Channels 7 and 8 of each Output are routed to the same Input A channels. 46 | - Channels 5 and 6 of Output B are unrouted. 47 | 48 | 49 | The above Map is represented in JSON in the API as below. See [Behaviour](Behaviour.md) for more details. 50 | 51 | ```json 52 | "map": { 53 | "OutputA": { 54 | "0": { 55 | "input": "InputA", 56 | "channel_index": 0 57 | }, 58 | "1": { 59 | "input": "InputA", 60 | "channel_index": 1 61 | }, 62 | ... etc. ... 63 | }, 64 | "OutputB": { 65 | "0": { 66 | "input": "InputB", 67 | "channel_index": 0 68 | }, 69 | ... etc. ... 70 | "4": { 71 | "input": null, 72 | "channel_index": null 73 | }, 74 | ... etc. ... 75 | "6": { 76 | "input": "InputA", 77 | "channel_index": 6 78 | }, 79 | ... etc. ... 80 | } 81 | } 82 | ``` 83 | 84 | The API has two representations of the Map. The "Active" Map describes the current channel mapping state of the Device. The Map's "Activations" represent the intended mapping changes of the Device at future points in time. An "Activation" is the process whereby the Active Map transitions to reflect the mapping changes. At the time of activation the underlying audio channel mapping behaviour of the Device transitions to reflect the new state of the Active map. 85 | 86 | An Activation may either be "immediate", "relatively scheduled" or "absolutely scheduled". Immediate activations are carried out as soon as possible after the request is received and SHOULD be completed before the response is sent. A relatively scheduled activation is carried out after a period of time specified by the client has elapsed. An absolute activation is carried out at a specific time specified by the client. 87 | 88 | ## API Structure 89 | 90 | The API is divided into the following parts: 91 | 92 | ### Inputs 93 | 94 | The `inputs` resource and its child resources enumerate all of the Inputs, their channels and routing constraints. It also exposes the `parent` resource, which is used to indicate the origin of the audio associated with that Input. 95 | 96 | These resources are read only. 97 | 98 | ### Outputs 99 | 100 | The `outputs` resource and its child resources enumerate all of the Outputs, including restrictions on which Inputs may be routed to an Output, and an optional Source ID, which represents the new NMOS Source created by re-mapping the audio. 101 | 102 | These resources are read only. 103 | 104 | ### Map 105 | 106 | The `map` resource has child resources that represent the Active Map and any pending Activations. The Active Map is not directly modifiable by the client - changes must be made by POSTing Activations. 107 | 108 | ### Inputs/Outputs View 109 | 110 | The `io` resource is simply a view onto data available elsewhere in the API, in order to allow clients to gather the information they need about inputs and outputs in a single request. 111 | 112 | This resource is read only. 113 | 114 | ## API Interaction 115 | 116 | The following sequence diagrams show the expected interactions with the IS-04 registry, a device's IS-05 Connection API and its Channel Mapping API in order to route a channel mapped audio stream to a receiver. 117 | 118 | The mapping can either take place on the receiving Device itself, or on the sending Device, depending on the capabilities and requirements of the system. 119 | 120 | ### Receiver Side Sequence Diagram 121 | 122 | ![receiver side channel mapping work-flow sequence diagram](images/sequence-diagrams/receiver-sequence.png "Receiver Side Sequence Diagram") 123 | 124 | ### Sender Side Sequence Diagram 125 | 126 | ![sender side channel mapping work-flow sequence diagram](images/sequence-diagrams/sender-sequence.png "Sender Side Sequence Diagram") 127 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | - [Overview](Overview.md) 2 | - [APIs](APIs.md) 3 | - [APIs - Client Side Implementation](APIs%20-%20Client%20Side%20Implementation.md) 4 | - [APIs - Server Side Implementation](APIs%20-%20Server%20Side%20Implementation.md) 5 | - [Interoperability](Interoperability.md) 6 | - [Interoperability - NMOS IS-04](Interoperability%20-%20NMOS%20IS-04.md) 7 | - [Behaviour](Behaviour.md) 8 | - [Upgrade Path](Upgrade%20Path.md) 9 | -------------------------------------------------------------------------------- /docs/Upgrade Path.md: -------------------------------------------------------------------------------- 1 | # Upgrade Path 2 | 3 | _(c) AMWA 2018, CC Attribution-NoDerivatives 4.0 International (CC BY-ND 4.0)_ 4 | 5 | As is common with web APIs, over time changes will be made to support new use cases and deprecate old ways of working. The NMOS APIs are no different, and have been designed to permit in-service upgrades across a facility which may be running large amounts of equipment with support for different versions of these specifications. 6 | 7 | API versioning is specified in the [APIs](APIs.md) documentation, with procedures for handling upgrades described below. 8 | 9 | ## Requirements for Channel Mapping APIs 10 | 11 | Implementers of the Channel Mapping API must support at least one API version, and may support more than one at a time. 12 | 13 | ## Requirements for Channel Mapping clients 14 | 15 | Implementers of Channel Mapping API clients are strongly recommended to support multiple versions of the Channel Mapping API simultaneously in order to ease the upgrade process in live facilities. 16 | 17 | ## Performing Upgrades 18 | 19 | The following procedure is suggested for a live system which needs to migrate between API versions. 20 | 21 | * Upgrade API clients to their new versions, which must support all Channel Mapping API versions you are currently using in your deployment. 22 | * Upgrade Chanel Mapping API implementations to support the new API version. 23 | -------------------------------------------------------------------------------- /docs/images/map-examples.graffle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMWA-TV/is-08/cf3bb58c26bf7927c7b857b641d0e8f9e29db188/docs/images/map-examples.graffle -------------------------------------------------------------------------------- /docs/images/map-examples/input-constraints-block-crossover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMWA-TV/is-08/cf3bb58c26bf7927c7b857b641d0e8f9e29db188/docs/images/map-examples/input-constraints-block-crossover.png -------------------------------------------------------------------------------- /docs/images/map-examples/input-constraints-block-input-gap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMWA-TV/is-08/cf3bb58c26bf7927c7b857b641d0e8f9e29db188/docs/images/map-examples/input-constraints-block-input-gap.png -------------------------------------------------------------------------------- /docs/images/map-examples/input-constraints-block-no-reordering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMWA-TV/is-08/cf3bb58c26bf7927c7b857b641d0e8f9e29db188/docs/images/map-examples/input-constraints-block-no-reordering.png -------------------------------------------------------------------------------- /docs/images/map-examples/input-constraints-block-reordering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMWA-TV/is-08/cf3bb58c26bf7927c7b857b641d0e8f9e29db188/docs/images/map-examples/input-constraints-block-reordering.png -------------------------------------------------------------------------------- /docs/images/map-examples/input-constraints-block-switching.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMWA-TV/is-08/cf3bb58c26bf7927c7b857b641d0e8f9e29db188/docs/images/map-examples/input-constraints-block-switching.png -------------------------------------------------------------------------------- /docs/images/map-examples/input-constraints-crossover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMWA-TV/is-08/cf3bb58c26bf7927c7b857b641d0e8f9e29db188/docs/images/map-examples/input-constraints-crossover.png -------------------------------------------------------------------------------- /docs/images/map-examples/input-constraints-gaps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMWA-TV/is-08/cf3bb58c26bf7927c7b857b641d0e8f9e29db188/docs/images/map-examples/input-constraints-gaps.png -------------------------------------------------------------------------------- /docs/images/map-examples/input-constraints-input-gap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMWA-TV/is-08/cf3bb58c26bf7927c7b857b641d0e8f9e29db188/docs/images/map-examples/input-constraints-input-gap.png -------------------------------------------------------------------------------- /docs/images/map-examples/input-constraints-no-reordering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMWA-TV/is-08/cf3bb58c26bf7927c7b857b641d0e8f9e29db188/docs/images/map-examples/input-constraints-no-reordering.png -------------------------------------------------------------------------------- /docs/images/map-examples/input-constraints-one-block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMWA-TV/is-08/cf3bb58c26bf7927c7b857b641d0e8f9e29db188/docs/images/map-examples/input-constraints-one-block.png -------------------------------------------------------------------------------- /docs/images/map-examples/input-constraints-switching.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMWA-TV/is-08/cf3bb58c26bf7927c7b857b641d0e8f9e29db188/docs/images/map-examples/input-constraints-switching.png -------------------------------------------------------------------------------- /docs/images/map-examples/re-entrant-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMWA-TV/is-08/cf3bb58c26bf7927c7b857b641d0e8f9e29db188/docs/images/map-examples/re-entrant-example.png -------------------------------------------------------------------------------- /docs/images/map-examples/terminology.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMWA-TV/is-08/cf3bb58c26bf7927c7b857b641d0e8f9e29db188/docs/images/map-examples/terminology.png -------------------------------------------------------------------------------- /docs/images/sequence-diagrams.graffle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMWA-TV/is-08/cf3bb58c26bf7927c7b857b641d0e8f9e29db188/docs/images/sequence-diagrams.graffle -------------------------------------------------------------------------------- /docs/images/sequence-diagrams/receiver-sequence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMWA-TV/is-08/cf3bb58c26bf7927c7b857b641d0e8f9e29db188/docs/images/sequence-diagrams/receiver-sequence.png -------------------------------------------------------------------------------- /docs/images/sequence-diagrams/sender-sequence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AMWA-TV/is-08/cf3bb58c26bf7927c7b857b641d0e8f9e29db188/docs/images/sequence-diagrams/sender-sequence.png -------------------------------------------------------------------------------- /examples/base-get-200.json: -------------------------------------------------------------------------------- 1 | [ 2 | "inputs/", 3 | "outputs/", 4 | "map/", 5 | "io/" 6 | ] -------------------------------------------------------------------------------- /examples/inputs/input-base-get-200.json: -------------------------------------------------------------------------------- 1 | [ 2 | "caps/", 3 | "parent/", 4 | "channels/", 5 | "properties/" 6 | ] 7 | -------------------------------------------------------------------------------- /examples/inputs/input-caps-get-200.json: -------------------------------------------------------------------------------- 1 | { 2 | "reordering": true, 3 | "block_size": 8 4 | } 5 | -------------------------------------------------------------------------------- /examples/inputs/input-channels-get-200.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "label": "Left Channel" 4 | }, 5 | { 6 | "label": "Right Channel" 7 | } 8 | ] 9 | -------------------------------------------------------------------------------- /examples/inputs/input-parent-get-200.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "91762591-9e46-48db-bd08-f8450248f02c", 3 | "type": "source" 4 | } 5 | -------------------------------------------------------------------------------- /examples/inputs/input-properties-get-200.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "AES-2", 3 | "description": "AES digital audio input 2" 4 | } -------------------------------------------------------------------------------- /examples/inputs/inputs-base-get-200.json: -------------------------------------------------------------------------------- 1 | [ 2 | "input1/", 3 | "input2/", 4 | "input3/", 5 | "input4/" 6 | ] 7 | -------------------------------------------------------------------------------- /examples/io-get-200.json: -------------------------------------------------------------------------------- 1 | { 2 | "inputs":{ 3 | "input1":{ 4 | "parent": { 5 | "id": "f6b34356-9885-4db8-bdeb-3141e23f443c", 6 | "type": "source" 7 | }, 8 | "channels":[ 9 | {"label": "outA"}, 10 | {"label": "outB"}, 11 | {"label": "outC"}, 12 | {"label": "outD"} 13 | ], 14 | "caps": { 15 | "reordering": false, 16 | "block_size": 2 17 | }, 18 | "properties":{ 19 | "name": "Input 2", 20 | "description": "Four channel input 2" 21 | } 22 | }, 23 | "input2":{ 24 | "parent": { 25 | "id": "3286c499-3e78-4125-b0e2-d465354d11e6", 26 | "type": "receiver" 27 | }, 28 | "channels":[ 29 | {"label": "FL"}, 30 | {"label": "FR"}, 31 | {"label": "LS"}, 32 | {"label": "RS"}, 33 | {"label": "C"}, 34 | {"label": "S"} 35 | ], 36 | "caps": { 37 | "reordering": true, 38 | "block_size": 1 39 | }, 40 | "properties":{ 41 | "name": "5.1 Input", 42 | "description": "Surround sound input" 43 | } 44 | }, 45 | "input3":{ 46 | "parent": { 47 | "id": null, 48 | "type": null 49 | }, 50 | "channels":[ 51 | {"label": "L"}, 52 | {"label": "R"} 53 | ], 54 | "caps": { 55 | "reordering": true, 56 | "block_size": 1 57 | }, 58 | "properties":{ 59 | "name": "Stereo Input 1", 60 | "description": "Stereo input on rear of unit" 61 | } 62 | }, 63 | "input4":{ 64 | "parent":{ 65 | "id": "6dea8109-9e27-49e7-81eb-65a74e964414", 66 | "type": "source" 67 | }, 68 | "channels":[ 69 | {"label": "a"}, 70 | {"label": "b"}, 71 | {"label": "c"} 72 | ], 73 | "caps": { 74 | "reordering": false, 75 | "block_size": 1 76 | }, 77 | "properties":{ 78 | "name": "Input 4", 79 | "description": "RTP Input" 80 | } 81 | } 82 | }, 83 | "outputs":{ 84 | "output1":{ 85 | "source_id": "bdebfc73-6f43-497a-a9c3-c822ea34a4c9", 86 | "channels":[ 87 | {"label": "outA"}, 88 | {"label": "outB"} 89 | ], 90 | "caps":{ 91 | "routable_inputs":[ 92 | "input1", 93 | "input2", 94 | "input4" 95 | ] 96 | }, 97 | "properties":{ 98 | "name": "Output 1", 99 | "description": "RTP Output One" 100 | } 101 | }, 102 | "output2":{ 103 | "source_id": "491de650-c47e-4b70-9597-72ebbf23372a", 104 | "channels":[ 105 | {"label": "L"}, 106 | {"label": "R"} 107 | ], 108 | "caps":{ 109 | "routable_inputs":[ 110 | "input3" 111 | ] 112 | }, 113 | "properties":{ 114 | "name": "Stereo Output", 115 | "description": "Stereo output on rear of unit" 116 | } 117 | } 118 | } 119 | } -------------------------------------------------------------------------------- /examples/map/map-activations-activation-get-200.json: -------------------------------------------------------------------------------- 1 | { 2 | "activation":{ 3 | "mode": "activate_scheduled_relative", 4 | "requested_time": "2:0", 5 | "activation_time": "1544448736:0" 6 | }, 7 | "action":{ 8 | "OutA":{ 9 | "0":{ 10 | "input": "input2", 11 | "channel_index": 1 12 | }, 13 | "3":{ 14 | "input": "input2", 15 | "channel_index": 1 16 | } 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /examples/map/map-activations-get-200.json: -------------------------------------------------------------------------------- 1 | { 2 | "1" :{ 3 | "activation":{ 4 | "mode": "activate_scheduled_absolute", 5 | "requested_time": "1544448739:0", 6 | "activation_time": "1544448739:0" 7 | }, 8 | "action":{ 9 | "OutA":{ 10 | "0":{ 11 | "input": "input1", 12 | "channel_index": 2 13 | }, 14 | "3":{ 15 | "input": "input1", 16 | "channel_index": 1 17 | } 18 | } 19 | } 20 | }, 21 | "2" :{ 22 | "activation":{ 23 | "mode": "activate_scheduled_relative", 24 | "requested_time": "2:0", 25 | "activation_time": "1544448736:0" 26 | }, 27 | "action":{ 28 | "OutA":{ 29 | "0":{ 30 | "input": "input2", 31 | "channel_index": 1 32 | }, 33 | "3":{ 34 | "input": "input2", 35 | "channel_index": 1 36 | } 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/map/map-activations-post-200.json: -------------------------------------------------------------------------------- 1 | { 2 | "3": { 3 | "activation":{ 4 | "mode": "activate_scheduled_absolute", 5 | "requested_time": "1544448739:0", 6 | "activation_time": "1544448739:0" 7 | }, 8 | "action":{ 9 | "OutA":{ 10 | "0":{ 11 | "input": "input1", 12 | "channel_index": 2 13 | }, 14 | "3":{ 15 | "input": "input1", 16 | "channel_index": 1 17 | } 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/map/map-activations-post-400.json: -------------------------------------------------------------------------------- 1 | { 2 | "code": 400, 3 | "error": "Could not match the request to the schema", 4 | "debug": null 5 | } 6 | -------------------------------------------------------------------------------- /examples/map/map-activations-post-423.json: -------------------------------------------------------------------------------- 1 | { 2 | "code": 423, 3 | "error": "Output 'OutA' is locked by another activation. No changes will be made.", 4 | "debug": null 5 | } 6 | -------------------------------------------------------------------------------- /examples/map/map-activations-post.json: -------------------------------------------------------------------------------- 1 | { 2 | "activation":{ 3 | "mode": "activate_scheduled_absolute", 4 | "requested_time": "1544448739:0" 5 | }, 6 | "action":{ 7 | "OutA":{ 8 | "0":{ 9 | "input": "input1", 10 | "channel_index": 2 11 | }, 12 | "3":{ 13 | "input": "input1", 14 | "channel_index": 1 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/map/map-active-get-200.json: -------------------------------------------------------------------------------- 1 | { 2 | "activation": { 3 | "mode": null, 4 | "requested_time": null, 5 | "activation_time": null 6 | }, 7 | "map":{ 8 | "outA":{ 9 | "0":{ 10 | "input": "input1", 11 | "channel_index": 1 12 | }, 13 | "1":{ 14 | "input": "input1", 15 | "channel_index": 2 16 | }, 17 | "2":{ 18 | "input": "input1", 19 | "channel_index": 3 20 | }, 21 | "3":{ 22 | "input": "input1", 23 | "channel_index": 4 24 | }, 25 | "4":{ 26 | "input": null, 27 | "channel_index": null 28 | }, 29 | "5":{ 30 | "input": null, 31 | "channel_index": null 32 | }, 33 | "6":{ 34 | "input": null, 35 | "channel_index": null 36 | }, 37 | "7":{ 38 | "input": null, 39 | "channel_index": null 40 | } 41 | }, 42 | "outB":{ 43 | "0":{ 44 | "input": "input4", 45 | "channel_index": 0 46 | }, 47 | "1":{ 48 | "input": "input4", 49 | "channel_index": 1 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /examples/map/map-active-output-get-200.json: -------------------------------------------------------------------------------- 1 | { 2 | "map":{ 3 | "outB":{ 4 | "0":{ 5 | "input": "input4", 6 | "channel_index": 0 7 | }, 8 | "1":{ 9 | "input": "input4", 10 | "channel_index": 1 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/map/map-base-get-200.json: -------------------------------------------------------------------------------- 1 | [ 2 | "activations/", 3 | "active/" 4 | ] 5 | -------------------------------------------------------------------------------- /examples/outputs/output-base-get-200.json: -------------------------------------------------------------------------------- 1 | [ 2 | "caps/", 3 | "sourceid/", 4 | "channels/", 5 | "properties/" 6 | ] 7 | -------------------------------------------------------------------------------- /examples/outputs/output-caps-get-200.json: -------------------------------------------------------------------------------- 1 | { 2 | "routable_inputs": [ 3 | "input1", 4 | "input2" 5 | ] 6 | } 7 | 8 | -------------------------------------------------------------------------------- /examples/outputs/output-channels-get-200.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "label": "Left Channel" 4 | }, 5 | { 6 | "label": "Right Channel" 7 | } 8 | ] 9 | -------------------------------------------------------------------------------- /examples/outputs/output-properties-get-200.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "IP Output", 3 | "description": "SMPTE 2110-30 IP Output" 4 | } 5 | -------------------------------------------------------------------------------- /examples/outputs/output-sourceid-get-200.json: -------------------------------------------------------------------------------- 1 | "066cde2f-a525-417b-9177-20ae536265bc" 2 | -------------------------------------------------------------------------------- /examples/outputs/outputs-base-get-200.json: -------------------------------------------------------------------------------- 1 | [ 2 | "OutA/", 3 | "OutB/" 4 | ] 5 | -------------------------------------------------------------------------------- /spec.yml: -------------------------------------------------------------------------------- 1 | amwa_id: IS-08 2 | url: https://specs.amwa.tv/is-08 3 | name: Audio Channel Mapping 4 | status: AMWA Specification (Stable) 5 | repo_name: is-08 6 | alt_repo_name: nmos-audio-channel-mapping 7 | repo_url: https://github.com/AMWA-TV/is-08 8 | releases: 9 | - v1.0.1 10 | default_branch: v1.0.x 11 | show_in_index: true 12 | --------------------------------------------------------------------------------