1{ 2 "$schema": "http://json-schema.org/draft-07/schema#", 3 "$id": "https://something/streaming_schema.json", 4 "definitions": { 5 "ssrc": {"type": "integer", "minimum": 0, "maximum": 4294967295}, 6 "delay": {"type": "integer", "minimum": 1, "maximum": 4000}, 7 "resolution": { 8 "width": {"type": "integer", "minimum": 320}, 9 "height": {"type": "integer", "minimum": 240} 10 }, 11 "frame_rate": { 12 "type": "string", 13 "pattern": "[0-9]+(/[0-9]+)?", 14 "examples": ["30", "30000/1001"] 15 }, 16 "dimensions": { 17 "allOf": [ 18 {"$ref": "#/definitions/resolution"}, 19 {"properties": {"frameRate": {"$ref": "#/definitions/frame_rate"}}} 20 ] 21 }, 22 "rtp_extensions": { 23 "type": "array", 24 "items": {"type": "string", "enum": ["adaptive_playout_delay"]} 25 }, 26 "stream": { 27 "properties": { 28 "index": {"type": "integer", "minimum": 0}, 29 "type": {"type": "string", "enum": ["audio_source", "video_source"]}, 30 "codecName": {"type": "string", "enum": ["aac", "opus", "h264", "vp8", "hevc", "vp9", "av1"]}, 31 "codecParameter": {"type": "string"}, 32 "rtpProfile": {"type": "string", "enum": ["cast"]}, 33 "rtpPayloadType": {"type": "integer", "minimum": 96, "maximum": 127}, 34 "ssrc": {"$ref": "#/definitions/ssrc"}, 35 "targetDelay": {"$ref": "#/definitions/delay"}, 36 "aesKey": {"type": "string", "pattern": "[0-9a-fA-F]{32}"}, 37 "aesIvMask": {"type": "string", "pattern": "[0-9a-fA-F]{32}"}, 38 "receiverRtcpEventLog": {"type": "boolean"}, 39 "receiverRtcpDscp": {"type": "integer", "minimum": 0, "default": 46}, 40 "rtpExtensions": {"$ref": "#/definitions/rtp_extensions"}, 41 "timeBase": { 42 "type": "string", 43 "pattern": "1/[0-9]+", 44 "default": "1/90000" 45 } 46 }, 47 "required": [ 48 "index", 49 "type", 50 "codecName", 51 "rtpPayloadType", 52 "ssrc", 53 "aesKey", 54 "aesIvMask", 55 "timeBase" 56 ] 57 }, 58 "audio_stream": { 59 "allOf": [ 60 {"$ref": "#/definitions/stream"}, 61 { 62 "properties": { 63 "bitRate": {"type": "integer", "minimum": 0}, 64 "channels": {"type": "integer", "minimum": 1} 65 }, 66 "required": ["bitRate", "channels"] 67 } 68 ] 69 }, 70 "video_stream": { 71 "allOf": [ 72 {"$ref": "#/definitions/stream"}, 73 { 74 "properties": { 75 "maxFrameRate": {"$ref": "#/definitions/frame_rate"}, 76 "maxBitRate": {"type": "integer", "minimum": 0}, 77 "resolutions": { 78 "type": "array", 79 "items": {"$ref": "#/definitions/resolution"} 80 }, 81 "errorRecoveryMode": { 82 "type": "string", 83 "enum": ["castv2", "intra_mb_refresh"], 84 "default": "castv2" 85 } 86 }, 87 "required": ["maxFrameRate", "maxBitRate", "resolutions"] 88 } 89 ] 90 }, 91 "offer": { 92 "properties": { 93 "supportedStreams": { 94 "type": "array", 95 "items": {"$ref": "#/definitions/stream"} 96 }, 97 "castMode": {"type": "string", "enum": ["mirroring", "remoting"]}, 98 "receiverStatus": {"type": "boolean"} 99 } 100 }, 101 "audio_constraints": { 102 "properties": { 103 "maxSampleRate": { 104 "type": "integer", 105 "minimum": 16000, 106 "default": 48000, 107 "maximum": 96000 108 }, 109 "maxChannels": {"type": "integer", "minimum": 1, "default": 2}, 110 "minBitRate": {"type": "integer", "minimum": 32000, "maximum": 320000}, 111 "maxBitRate": {"type": "integer", "minimum": 32000, "maximum": 320000}, 112 "maxDelay": {"$ref": "#/definitions/delay"} 113 }, 114 "required": ["maxSampleRate", "maxChannels", "maxBitRate"] 115 }, 116 "video_constraints": { 117 "properties": { 118 "maxPixelsPerSecond": {"type": "number", "minimum": 0}, 119 "minResolution": {"$ref": "#/definitions/resolution"}, 120 "maxDimensions": {"$ref": "#/definitions/dimensions"}, 121 "minBitRate": {"type": "integer", "minimum": 300000}, 122 "maxBitRate": {"type": "integer", "minimum": 300000}, 123 "maxDelay": {"$ref": "#/definitions/delay"} 124 }, 125 "required": ["maxDimensions", "maxBitRate"] 126 }, 127 "constraints": { 128 "properties": { 129 "audio": {"$ref": "#/definitions/audio_constraints"}, 130 "video": {"$ref": "#/definitions/video_constraints"} 131 }, 132 "required": ["audio", "video"] 133 }, 134 "display": { 135 "$id": "#display", 136 "properties": { 137 "dimensions": {"$ref": "#/definitions/dimensions"}, 138 "aspectRatio": {"type": "string", "pattern": "[0-9]+:[0-9]+"}, 139 "scaling": {"type": "string", "enum": ["sender", "receiver"]} 140 }, 141 "required": [] 142 }, 143 "error": { 144 "properties": { 145 "code": {"type": "integer"}, 146 "description": {"type": "string"} 147 }, 148 "required": ["code", "description"] 149 }, 150 "answer": { 151 "type": "object", 152 "properties": { 153 "udpPort": {"type": "integer", "minimum": 1, "maximum": 65535}, 154 "sendIndexes": { 155 "type": "array", 156 "items": {"type": "integer", "minimum": 0} 157 }, 158 "ssrcs": {"type": "array", "items": {"$ref": "#/definitions/ssrc"}}, 159 "constraints": {"$ref": "#/definitions/constraints"}, 160 "display": {"$ref": "#/definitions/display"}, 161 "receiverRtcpEventLog": { 162 "type": "array", 163 "items": {"type": "integer", "minimum": 0} 164 }, 165 "receiverRtcpDscp": { 166 "type": "array", 167 "items": {"type": "integer", "minimum": 0} 168 }, 169 "rtpExtensions": {"$ref": "#/definitions/rtp_extensions"} 170 }, 171 "required": ["udpPort", "sendIndexes", "ssrcs"] 172 }, 173 "capabilities": { 174 "$id": "#capabilities", 175 "type": "object", 176 "properties": { 177 "mediaCaps": { 178 "type": "array", 179 "items": { 180 "type": "string", 181 "enum": [ 182 "audio", 183 "aac", 184 "opus", 185 "video", 186 "4k", 187 "h264", 188 "vp8", 189 "hevc", 190 "vp9" 191 ] 192 } 193 }, 194 "remoting": {"type": "integer"} 195 }, 196 "required": ["mediaCaps"] 197 } 198 }, 199 "type": "object", 200 "properties": { 201 "offer": {"$ref": "#/definitions/offer"}, 202 "answer": {"$ref": "#/definitions/answer"}, 203 "capabilities": {"$ref": "#/definitions/capabilities"}, 204 "error": {"$ref": "#/definitions/error"}, 205 "result": {"type": "string", "enum": ["ok", "error"]}, 206 "seqNum": {"type": "integer", "minimum": 0}, 207 "sessionId": {"type": "integer"}, 208 "type": { 209 "type": "string", 210 "enum": [ 211 "OFFER", 212 "ANSWER", 213 "GET_STATUS", 214 "STATUS_RESPONSE", 215 "GET_CAPABILITIES", 216 "CAPABILITIES_RESPONSE", 217 "RPC" 218 ] 219 } 220 }, 221 "required": ["type"], 222 "allOf": [ 223 { 224 "if": { 225 "properties": { 226 "type": { 227 "enum": ["ANSWER", "CAPABILITIES_RESPONSE", "STATUS_RESPONSE"] 228 } 229 } 230 }, 231 "then": {"required": ["result"]} 232 }, 233 { 234 "if": { 235 "properties": { 236 "type": { 237 "enum": [ 238 "OFFER", 239 "ANSWER", 240 "GET_CAPABILITIES", 241 "CAPABILITIES_RESPONSE", 242 "GET_STATUS", 243 "STATUS_RESPONSE" 244 ] 245 } 246 } 247 }, 248 "then": {"required": ["seqNum"]} 249 }, 250 { 251 "if": {"properties": {"type": {"const": "OFFER"}}}, 252 "then": {"required": ["offer"]} 253 }, 254 { 255 "if": { 256 "properties": {"type": {"const": "ANSWER"}, "result": {"const": "ok"}} 257 }, 258 "then": {"required": ["answer"]} 259 }, 260 { 261 "if": { 262 "properties": { 263 "type": {"const": "CAPABILITIES_RESPONSE"}, 264 "result": {"const": "ok"} 265 } 266 }, 267 "then": {"required": ["capabilities"]} 268 }, 269 { 270 "if": { 271 "properties": {"type": {"const": "RPC"}, "result": {"const": "ok"}} 272 }, 273 "then": {"required": ["rpc"]} 274 } 275 ] 276} 277