This commit is contained in:
unfunny
2026-09-12 23:57:45 -04:00
parent 986c0af682
commit dfe4cc537f
1775 changed files with 246421 additions and 0 deletions

19
node_modules/sdp-transform/.eslintrc.js generated vendored Normal file
View File

@@ -0,0 +1,19 @@
module.exports = {
'env': {
'browser': true,
'commonjs': true,
'es6' : true
},
'extends': 'eslint:recommended',
'globals': {
'process': false,
'__dirname': false
},
'rules': {
'indent': ['error', 2],
'linebreak-style': ['error', 'unix'],
'quotes': ['error', 'single'],
'semi': ['error', 'always'],
'no-console': 0
}
};

12
node_modules/sdp-transform/.github/FUNDING.yml generated vendored Normal file
View File

@@ -0,0 +1,12 @@
# These are supported funding model platforms
github: [clux]
#patreon: # Replace with a single Patreon username
#open_collective: # Replace with a single Open Collective username
#ko_fi: # Replace with a single Ko-fi username
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
#liberapay: # Replace with a single Liberapay username
#issuehunt: # Replace with a single IssueHunt username
#otechie: # Replace with a single Otechie username
#custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

8
node_modules/sdp-transform/.github/codecov.yml generated vendored Normal file
View File

@@ -0,0 +1,8 @@
comment:
require_changes: no
layout: "diff,files"
coverage:
status:
project:
project: off
patch: off

15
node_modules/sdp-transform/.github/dependabot.yml generated vendored Normal file
View File

@@ -0,0 +1,15 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
labels:
- "dependencies"
#- package-ecosystem: "npm"
# directory: "/"
# schedule:
# interval: "monthly"
# labels:
# - "dependencies"

26
node_modules/sdp-transform/.github/workflows/ci.yml generated vendored Normal file
View File

@@ -0,0 +1,26 @@
name: CI
on:
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 'lts/*'
- run: npm install
- run: npm run lint
- run: npm test
coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 'lts/*'
- run: npm install
- run: npm run coverage
- uses: codecov/codecov-action@v3

247
node_modules/sdp-transform/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,247 @@
3.0.0 / 2025-10-26
===================
* allow multiple `a=msid` attributes #104
2.15.0 / 2024-11-26
===================
* Expose `grammar` object to allow injecting custom rules #103
2.14.2 / 2024-01-29
===================
* Release a new version to prove we actually exist #102
2.14.1 / 2020-12-02
===================
* Fix `a=rtcp-fb` bug where trr-int is `*` via #91
2.14.0 / 2020-01-22
===================
* Add `a=ptime` now support float values for sub-ms values via #89
2.13.0 / 2019-09-29
===================
* Add `a=ts-refclk` and `a=mediaclk` for RFC7273 support via #78
2.12.0 / 2019-08-05
===================
* a=extmap-allow-mixed (RFC 8285) #87
2.11.0 / 2019-07-28
===================
* BFCP RFC4583 support via #86
2.10.0 / 2019-07-12
===================
* `a=connection` support for RFC4145 via #85
2.9.0 / 2019-07-11
==================
* `a=keywds` support via #82
2.8.0 / 2019-05-29
==================
* `a=extmap` `encrypt-uri` improvements in #81
* `parsePayloads` safe parsing bugfix for integer equivalent m-lines #80
2.7.0 / 2018-11-21
==================
* `a=sctp-port` + `a=max-message-size` support added in #76 via @egzonzeneli
2.6.0 / 2018-11-14
==================
* `a=label` support added in #75 via @jeremy-j-ackso
2.5.0 / 2018-11-02
==================
* `a=bundle-only` support added in #73 via @ibc
2.4.1 / 2018-04-02
==================
* `parseParams` now doesn't break on name only params #70 via @manuc66
2.4.0 / 2018-01-24
==================
* `a=source-filter` support added in #69 via @thosil
2.3.1 / 2018-01-05
==================
* `a=ssrc` bug attributes including dashes fixed in #68 via @MichelSimonot
2.3.0 / 2017-03-06
==================
* `a=framerate` from rfc4566 now parseable - #63 via @gregpabian
2.2.0 / 2017-03-05
==================
* `a=rid` now parseable - #59 from @ibc
* `parseFmtpConfig` now aliased as `parseParams` - works on a more general level - #60
* `parseFmtpConfig` deprecated - will be removed in 3.0.0
* `a=imageattr` now parseable - #61 from @ibc
* `parseImageattrParams` for extended image attr parsing RFC6236 - #61
* `a=simulcast` now parseable (both draft version 3 and draft v7) - #62 from @ibc
- `parseSimulcastStreamList` for more detailed simulcast parsing - #62
2.1.0 / 2017-03-02
==================
* `a=x-google-flag:%s` now parseable - #58 via @ibc
2.0.1 / 2017-02-20
==================
* a=ssrc-group parsing now doesn't break on dash-separation #54 via @murillo128
2.0.0 / 2017-02-16
==================
* a=extmap lines now parsed into a 4 object struct rather than a broken 3 object compound struct - #51 via @ibc
* this is unlikely to be breaking, but we major bumped just to be sure
1.7.0 / 2016-12-09
==================
* a=ssrc lines now properly handle attributes without values - #40 via @zxcpoiu
* a=candidate now supports network-id and network-cost values - #49 via @zxcpoiu
1.6.2 / 2016-03-23
==================
* Fix `a=rtpmap` parsing when codec included dots - #44 via @alexanderklintstrom
1.6.1 / 2016-03-18
==================
* Fix parsing of fmtp parameters with base64 in `parseFmtpConfig` - #42 via @lmoj
1.6.0 / 2016-03-02
==================
* Add support for `a=sctpmap` - #41 via @6uliver
1.5.3 / 2015-11-25
==================
* Parse tcp ice-candidates with raddr + rport correctly - #37 via @damencho
1.5.2 / 2015-11-17
==================
* Parse tcp ice-candidates lines correctly - #35 via @virtuacoplenny
1.5.1 / 2015-11-15
==================
* Added `.npmignore`
1.5.0 / 2015-09-05
==================
* Suport AirTunes a=rtpmap lines without clockrate #30 - via @DuBistKomisch
1.4.1 / 2015-08-14
==================
* Proper handling of whitespaces in a=fmtp: lines #29 - via @bgrozev
* `parseFmtpConfig` helper also handles whitespaces properly
1.4.0 / 2015-03-18
==================
* Add support for `a=rtcp-rsize`
1.3.0 / 2015-03-16
==================
* Add support for `a=end-of-candidates` trickle ice attribute
1.2.1 / 2015-03-15
==================
* Add parsing for a=ssrc-group
1.2.0 / 2015-03-05
==================
* a=msid attributes support and msid-semantic improvements
* writer now ignores `undefined` or `null` values
1.1.0 / 2014-10-20
==================
* Add support for parsing session level `a=ice-lite`
1.0.0 / 2014-09-30
==================
* Be more lenient with nelines. Allow \r\n, \r or \n.
0.6.1 / 2014-07-25
==================
* Documentation and test coverage release
0.6.0 / 2014-02-18
==================
* invalid a= lines are now parsed verbatim in `media[i].invalid` (#19)
* everything in `media[i].invalid` is written out verbatim (#19)
* add basic RTSP support (a=control lines) (#20)
0.5.3 / 2014-01-17
==================
* ICE candidates now parsed fully (no longer ignoring optional attrs) (#13)
0.5.2 / 2014-01-17
==================
* Remove `util` dependency to help browserify users
* Better parsing of `a=extmap`, `a=crypto` and `a=rtcp-fb` lines
* `sdp-verify` bin file included to help discover effects of `write ∘ parse`
0.5.1 / 2014-01-16
==================
* Correctly parse a=rtpmap with telephone-event codec #16
* Correctly parse a=rtcp lines that conditionally include the IP #16
0.5.0 / 2014-01-14
==================
* Enforce spec mandated \r\n line endings over \n (#15)
* Parsing of opus rtpmap wrong because encoding parameters were discarded (#12)
0.4.1 / 2013-12-19
==================
* Changed 'sendrecv' key on media streams to be called 'direction' to match SDP related RFCs (thanks to @saghul)
0.3.3 / 2013-12-10
==================
* Fixed a bug that caused time description lines ("t=" and "z=") to be in the wrong place
0.3.2 / 2013-10-21
==================
* Fixed a bug where large sessionId values where being rounded (#8)
* Optionally specify the `outerOrder` and `innerOrder` for the writer (allows working around Chrome not following the RFC specified order in #7)
0.3.1 / 2013-10-19
==================
* Fixed a bug that meant the writer didn't write the last newline (#6)
0.3.0 / 2013-10-18
==================
* Changed ext grammar to parse id and direction as one (fixes writing bug)
* Allow mid to be a string (fixes bug)
* Add support for maxptime value
* Add support for ice-options
* Add support for grouping frameworks
* Add support for msid-semantic
* Add support for ssrc
* Add support for rtcp-mux
* Writer improvements: add support for session level push attributes
0.2.1 / 2013-07-31
==================
* Support release thanks to @legastero, following was pulled from his fork:
* Add support for rtcp-fb attributes.
* Add support for header extension (extmap) attributes.
* Add support for crypto attributes.
* Add remote-candidates attribute support and parser.
0.2.0 / 2013-07-27
==================
* parse most normal lines sensibly
* factored out grammar properly
* added a writer that uses common grammar
* stop preprocessing parse object explicitly (so that parser ∘ writer == Id)
these parser helpers are instead exposed (may in the future be extended)
0.1.0 / 2013-07-21
==================
* rewrite parsing mechanism
* parse origin lines more efficiently
* parsing output now significantly different
0.0.2 / 2012-07-18
==================
* ice properties parsed
0.0.1 / 2012-07-17
==================
* Original release

22
node_modules/sdp-transform/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,22 @@
(The MIT License)
Copyright (c) 2013 Eirik Albrigtsen
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

254
node_modules/sdp-transform/README.md generated vendored Normal file
View File

@@ -0,0 +1,254 @@
# SDP Transform
[![npm status](http://img.shields.io/npm/v/sdp-transform.svg)](https://www.npmjs.org/package/sdp-transform)
[![CI](https://github.com/clux/sdp-transform/actions/workflows/ci.yml/badge.svg)](https://github.com/clux/sdp-transform/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/clux/sdp-transform/graph/badge.svg?token=OqDbVhIP3f)](https://codecov.io/gh/clux/sdp-transform)
A simple parser and writer of SDP. Defines internal grammar based on [RFC4566 - SDP](http://tools.ietf.org/html/rfc4566), [RFC5245 - ICE](http://tools.ietf.org/html/rfc5245), and many more.
For simplicity it will force values that are integers to integers and leave everything else as strings when parsing. The module should be simple to extend or build upon, and is constructed rigorously.
## Installation
```bash
$ npm install sdp-transform
```
## TypeScript Definitions
Available in the [@types/sdp-transform](https://www.npmjs.com/package/@types/sdp-transform) package:
```bash
$ npm install -D @types/sdp-transform
```
## Usage
Load using CommonJS syntax or ES6 syntax:
```js
// CommonJS
const sdpTransform = require('sdp-transform');
// ES6
import * as sdpTransform from 'sdp-transform';
```
## Usage - Parser
Pass it an unprocessed SDP string.
```js
const sdpStr = "v=0\r\n\
o=- 20518 0 IN IP4 203.0.113.1\r\n\
s= \r\n\
t=0 0\r\n\
c=IN IP4 203.0.113.1\r\n\
a=ice-ufrag:F7gI\r\n\
a=ice-pwd:x9cml/YzichV2+XlhiMu8g\r\n\
a=fingerprint:sha-1 42:89:c5:c6:55:9d:6e:c8:e8:83:55:2a:39:f9:b6:eb:e9:a3:a9:e7\r\n\
m=audio 54400 RTP/SAVPF 0 96\r\n\
a=rtpmap:0 PCMU/8000\r\n\
a=rtpmap:96 opus/48000\r\n\
a=ptime:20\r\n\
a=sendrecv\r\n\
a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host\r\n\
a=candidate:1 2 UDP 2113667326 203.0.113.1 54401 typ host\r\n\
m=video 55400 RTP/SAVPF 97 98\r\n\
a=rtpmap:97 H264/90000\r\n\
a=fmtp:97 profile-level-id=4d0028;packetization-mode=1\r\n\
a=rtpmap:98 VP8/90000\r\n\
a=sendrecv\r\n\
a=candidate:0 1 UDP 2113667327 203.0.113.1 55400 typ host\r\n\
a=candidate:1 2 UDP 2113667326 203.0.113.1 55401 typ host\r\n\
";
const res = sdpTransform.parse(sdpStr);
// =>
{ version: 0,
origin:
{ username: '-',
sessionId: 20518,
sessionVersion: 0,
netType: 'IN',
ipVer: 4,
address: '203.0.113.1' },
name: '',
timing: { start: 0, stop: 0 },
connection: { version: 4, ip: '203.0.113.1' },
iceUfrag: 'F7gI',
icePwd: 'x9cml/YzichV2+XlhiMu8g',
fingerprint:
{ type: 'sha-1',
hash: '42:89:c5:c6:55:9d:6e:c8:e8:83:55:2a:39:f9:b6:eb:e9:a3:a9:e7' },
media:
[ { rtp: [Object],
fmtp: [],
type: 'audio',
port: 54400,
protocol: 'RTP/SAVPF',
payloads: '0 96',
ptime: 20,
direction: 'sendrecv',
candidates: [Object] },
{ rtp: [Object],
fmtp: [Object],
type: 'video',
port: 55400,
protocol: 'RTP/SAVPF',
payloads: '97 98',
direction: 'sendrecv',
candidates: [Object] } ] }
// each media line is parsed into the following format
res.media[1];
// =>
{ rtp:
[ { payload: 97,
codec: 'H264',
rate: 90000 },
{ payload: 98,
codec: 'VP8',
rate: 90000 } ],
fmtp:
[ { payload: 97,
config: 'profile-level-id=4d0028;packetization-mode=1' } ],
type: 'video',
port: 55400,
protocol: 'RTP/SAVPF',
payloads: '97 98',
direction: 'sendrecv',
candidates:
[ { foundation: 0,
component: 1,
transport: 'UDP',
priority: 2113667327,
ip: '203.0.113.1',
port: 55400,
type: 'host' },
{ foundation: 1,
component: 2,
transport: 'UDP',
priority: 2113667326,
ip: '203.0.113.1',
port: 55401,
type: 'host' } ] }
```
In this example, only slightly dodgy string coercion case here is for `candidates[i].foundation`, which can be a string, but in this case can be equally parsed as an integer.
### Parser Postprocessing
No excess parsing is done to the raw strings apart from maybe coercing to ints, because the writer is built to be the inverse of the parser. That said, a few helpers have been built in:
#### parseParams()
Parses `fmtp.config` and others such as `rid.params` and returns an object with all the params in a key/value fashion.
```js
// to parse the fmtp.config from the previous example
sdpTransform.parseParams(res.media[1].fmtp[0].config);
// =>
{ 'profile-level-id': '4d0028',
'packetization-mode': 1 }
```
#### parsePayloads()
Returns an array with all the payload advertised in the main m-line.
```js
// what payloads where actually advertised in the main m-line ?
sdpTransform.parsePayloads(res.media[1].payloads);
// =>
[97, 98]
```
#### parseImageAttributes()
Parses [Generic Image Attributes](https://tools.ietf.org/html/rfc6236). Must be provided with the `attrs1` or `attrs2` string of a `a=imageattr` line. Returns an array of key/value objects.
```js
// a=imageattr:97 send [x=1280,y=720] recv [x=1280,y=720] [x=320,y=180]
sdpTransform.parseImageAttributes(res.media[1].imageattrs[0].attrs2)
// =>
[ {'x': 1280, 'y': 720}, {'x': 320, 'y': 180} ]
```
#### parseSimulcastStreamList()
Parses [simulcast](https://tools.ietf.org/html/draft-ietf-mmusic-sdp-simulcast) streams/formats. Must be provided with the `list1` or `list2` string of the `a=simulcast` line.
Returns an array of simulcast streams. Each entry is an array of alternative simulcast formats, which are objects with two keys:
* `scid`: Simulcast identifier
* `paused`: Whether the simulcast format is paused
```js
// a=simulcast:send 1,~4;2;3 recv c
sdpTransform.parseSimulcastStreamList(res.media[1].simulcast.list1);
// =>
[
// First simulcast stream (two alternative formats)
[ {scid: 1, paused: false}, {scid: 4, paused: true} ],
// Second simulcast stream
[ {scid: 2, paused: false} ],
// Third simulcast stream
[ {scid: 3, paused: false} ]
]
```
## Usage - Writer
The writer is the inverse of the parser, and will need a struct equivalent to the one returned by it.
```js
sdpTransform.write(res).split('\r\n'); // res parsed above
// =>
[ 'v=0',
'o=- 20518 0 IN IP4 203.0.113.1',
's= ',
'c=IN IP4 203.0.113.1',
't=0 0',
'a=ice-ufrag:F7gI',
'a=ice-pwd:x9cml/YzichV2+XlhiMu8g',
'a=fingerprint:sha-1 42:89:c5:c6:55:9d:6e:c8:e8:83:55:2a:39:f9:b6:eb:e9:a3:a9:e7',
'm=audio 54400 RTP/SAVPF 0 96',
'a=rtpmap:0 PCMU/8000',
'a=rtpmap:96 opus/48000',
'a=ptime:20',
'a=sendrecv',
'a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host',
'a=candidate:1 2 UDP 2113667326 203.0.113.1 54401 typ host',
'm=video 55400 RTP/SAVPF 97 98',
'a=rtpmap:97 H264/90000',
'a=rtpmap:98 VP8/90000',
'a=fmtp:97 profile-level-id=4d0028;packetization-mode=1',
'a=sendrecv',
'a=candidate:0 1 UDP 2113667327 203.0.113.1 55400 typ host',
'a=candidate:1 2 UDP 2113667326 203.0.113.1 55401 typ host' ]
```
The only thing different from the original input is we follow the order specified by the SDP RFC, and we will always do so.
## Usage - Custom grammar
In case you need to add custom grammar (e.g. add unofficial attributes) to the parser, you can do so by mutating the `grammar` object before parsing.
```js
sdpTransform.grammar['a'].push({
name: 'xCustomTag',
reg: /^x-custom-tag:(\d*)/,
names: ['tagId'],
format: 'x-custom-tag:%d
})
```
## License
MIT-Licensed. See LICENSE file for details.

47
node_modules/sdp-transform/checker.js generated vendored Executable file
View File

@@ -0,0 +1,47 @@
#!/usr/bin/env node
var transform = require('./')
, file = require('path').join(process.cwd(), process.argv[2])
, sdp = require('fs').readFileSync(file).toString()
, parsed = transform.parse(sdp)
, written = transform.write(parsed)
, writtenLines = written.split('\r\n')
, origLines = sdp.split('\r\n')
, numMissing = 0
, numNew = 0
;
var parseFails = 0;
parsed.media.forEach(function (media) {
(media.invalid || []).forEach(function (inv) {
console.warn('unrecognized a=' + inv.value + ' belonging to m=' + media.type);
parseFails += 1;
});
});
var parseStr = parseFails + ' unrecognized line(s) copied blindly';
origLines.forEach(function (line, i) {
if (writtenLines.indexOf(line) < 0) {
console.error('l' + i + ' lost (' + line + ')');
numMissing += 1;
}
});
writtenLines.forEach(function (line, i) {
if (origLines.indexOf(line) < 0) {
console.error('l' + i + ' new (' + line + ')');
numNew += 1;
}
});
var failed = (numMissing > 0 || numNew > 0);
if (failed) {
console.log('\n' + file + ' changes during transform:');
console.log(numMissing + ' missing line(s), ' + numNew + ' new line(s)%s',
parseFails > 0 ? ', ' + parseStr : ''
);
}
else {
console.log(file + ' verified%s', parseFails > 0 ? ', but had ' + parseStr : '');
}
process.exit(failed ? 1 : 0);

495
node_modules/sdp-transform/lib/grammar.js generated vendored Normal file
View File

@@ -0,0 +1,495 @@
var grammar = module.exports = {
v: [{
name: 'version',
reg: /^(\d*)$/
}],
o: [{
// o=- 20518 0 IN IP4 203.0.113.1
// NB: sessionId will be a String in most cases because it is huge
name: 'origin',
reg: /^(\S*) (\d*) (\d*) (\S*) IP(\d) (\S*)/,
names: ['username', 'sessionId', 'sessionVersion', 'netType', 'ipVer', 'address'],
format: '%s %s %d %s IP%d %s'
}],
// default parsing of these only (though some of these feel outdated)
s: [{ name: 'name' }],
i: [{ name: 'description' }],
u: [{ name: 'uri' }],
e: [{ name: 'email' }],
p: [{ name: 'phone' }],
z: [{ name: 'timezones' }], // TODO: this one can actually be parsed properly...
r: [{ name: 'repeats' }], // TODO: this one can also be parsed properly
// k: [{}], // outdated thing ignored
t: [{
// t=0 0
name: 'timing',
reg: /^(\d*) (\d*)/,
names: ['start', 'stop'],
format: '%d %d'
}],
c: [{
// c=IN IP4 10.47.197.26
name: 'connection',
reg: /^IN IP(\d) (\S*)/,
names: ['version', 'ip'],
format: 'IN IP%d %s'
}],
b: [{
// b=AS:4000
push: 'bandwidth',
reg: /^(TIAS|AS|CT|RR|RS):(\d*)/,
names: ['type', 'limit'],
format: '%s:%s'
}],
m: [{
// m=video 51744 RTP/AVP 126 97 98 34 31
// NB: special - pushes to session
// TODO: rtp/fmtp should be filtered by the payloads found here?
reg: /^(\w*) (\d*) ([\w/]*)(?: (.*))?/,
names: ['type', 'port', 'protocol', 'payloads'],
format: '%s %d %s %s'
}],
a: [
{
// a=rtpmap:110 opus/48000/2
push: 'rtp',
reg: /^rtpmap:(\d*) ([\w\-.]*)(?:\s*\/(\d*)(?:\s*\/(\S*))?)?/,
names: ['payload', 'codec', 'rate', 'encoding'],
format: function (o) {
return (o.encoding)
? 'rtpmap:%d %s/%s/%s'
: o.rate
? 'rtpmap:%d %s/%s'
: 'rtpmap:%d %s';
}
},
{
// a=fmtp:108 profile-level-id=24;object=23;bitrate=64000
// a=fmtp:111 minptime=10; useinbandfec=1
push: 'fmtp',
reg: /^fmtp:(\d*) ([\S| ]*)/,
names: ['payload', 'config'],
format: 'fmtp:%d %s'
},
{
// a=control:streamid=0
name: 'control',
reg: /^control:(.*)/,
format: 'control:%s'
},
{
// a=rtcp:65179 IN IP4 193.84.77.194
name: 'rtcp',
reg: /^rtcp:(\d*)(?: (\S*) IP(\d) (\S*))?/,
names: ['port', 'netType', 'ipVer', 'address'],
format: function (o) {
return (o.address != null)
? 'rtcp:%d %s IP%d %s'
: 'rtcp:%d';
}
},
{
// a=rtcp-fb:98 trr-int 100
push: 'rtcpFbTrrInt',
reg: /^rtcp-fb:(\*|\d*) trr-int (\d*)/,
names: ['payload', 'value'],
format: 'rtcp-fb:%s trr-int %d'
},
{
// a=rtcp-fb:98 nack rpsi
push: 'rtcpFb',
reg: /^rtcp-fb:(\*|\d*) ([\w-_]*)(?: ([\w-_]*))?/,
names: ['payload', 'type', 'subtype'],
format: function (o) {
return (o.subtype != null)
? 'rtcp-fb:%s %s %s'
: 'rtcp-fb:%s %s';
}
},
{
// a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
// a=extmap:1/recvonly URI-gps-string
// a=extmap:3 urn:ietf:params:rtp-hdrext:encrypt urn:ietf:params:rtp-hdrext:smpte-tc 25@600/24
push: 'ext',
reg: /^extmap:(\d+)(?:\/(\w+))?(?: (urn:ietf:params:rtp-hdrext:encrypt))? (\S*)(?: (\S*))?/,
names: ['value', 'direction', 'encrypt-uri', 'uri', 'config'],
format: function (o) {
return (
'extmap:%d' +
(o.direction ? '/%s' : '%v') +
(o['encrypt-uri'] ? ' %s' : '%v') +
' %s' +
(o.config ? ' %s' : '')
);
}
},
{
// a=extmap-allow-mixed
name: 'extmapAllowMixed',
reg: /^(extmap-allow-mixed)/
},
{
// a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR|2^20|1:32
push: 'crypto',
reg: /^crypto:(\d*) ([\w_]*) (\S*)(?: (\S*))?/,
names: ['id', 'suite', 'config', 'sessionConfig'],
format: function (o) {
return (o.sessionConfig != null)
? 'crypto:%d %s %s %s'
: 'crypto:%d %s %s';
}
},
{
// a=setup:actpass
name: 'setup',
reg: /^setup:(\w*)/,
format: 'setup:%s'
},
{
// a=connection:new
name: 'connectionType',
reg: /^connection:(new|existing)/,
format: 'connection:%s'
},
{
// a=mid:1
name: 'mid',
reg: /^mid:([^\s]*)/,
format: 'mid:%s'
},
{
// a=msid:0c8b064d-d807-43b4-b434-f92a889d8587 98178685-d409-46e0-8e16-7ef0db0db64a
push: 'msid',
reg: /^msid:([\w-]+)(?: ([\w-]+))?/,
names: ['id', 'appdata'],
format: 'msid:%s %s'
},
{
// a=ptime:20
name: 'ptime',
reg: /^ptime:(\d*(?:\.\d*)*)/,
format: 'ptime:%d'
},
{
// a=maxptime:60
name: 'maxptime',
reg: /^maxptime:(\d*(?:\.\d*)*)/,
format: 'maxptime:%d'
},
{
// a=sendrecv
name: 'direction',
reg: /^(sendrecv|recvonly|sendonly|inactive)/
},
{
// a=ice-lite
name: 'icelite',
reg: /^(ice-lite)/
},
{
// a=ice-ufrag:F7gI
name: 'iceUfrag',
reg: /^ice-ufrag:(\S*)/,
format: 'ice-ufrag:%s'
},
{
// a=ice-pwd:x9cml/YzichV2+XlhiMu8g
name: 'icePwd',
reg: /^ice-pwd:(\S*)/,
format: 'ice-pwd:%s'
},
{
// a=fingerprint:SHA-1 00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33
name: 'fingerprint',
reg: /^fingerprint:(\S*) (\S*)/,
names: ['type', 'hash'],
format: 'fingerprint:%s %s'
},
{
// a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
// a=candidate:1162875081 1 udp 2113937151 192.168.34.75 60017 typ host generation 0 network-id 3 network-cost 10
// a=candidate:3289912957 2 udp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 generation 0 network-id 3 network-cost 10
// a=candidate:229815620 1 tcp 1518280447 192.168.150.19 60017 typ host tcptype active generation 0 network-id 3 network-cost 10
// a=candidate:3289912957 2 tcp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 tcptype passive generation 0 network-id 3 network-cost 10
push:'candidates',
reg: /^candidate:(\S*) (\d*) (\S*) (\d*) (\S*) (\d*) typ (\S*)(?: raddr (\S*) rport (\d*))?(?: tcptype (\S*))?(?: generation (\d*))?(?: network-id (\d*))?(?: network-cost (\d*))?/,
names: ['foundation', 'component', 'transport', 'priority', 'ip', 'port', 'type', 'raddr', 'rport', 'tcptype', 'generation', 'network-id', 'network-cost'],
format: function (o) {
var str = 'candidate:%s %d %s %d %s %d typ %s';
str += (o.raddr != null) ? ' raddr %s rport %d' : '%v%v';
// NB: candidate has three optional chunks, so %void middles one if it's missing
str += (o.tcptype != null) ? ' tcptype %s' : '%v';
if (o.generation != null) {
str += ' generation %d';
}
str += (o['network-id'] != null) ? ' network-id %d' : '%v';
str += (o['network-cost'] != null) ? ' network-cost %d' : '%v';
return str;
}
},
{
// a=end-of-candidates (keep after the candidates line for readability)
name: 'endOfCandidates',
reg: /^(end-of-candidates)/
},
{
// a=remote-candidates:1 203.0.113.1 54400 2 203.0.113.1 54401 ...
name: 'remoteCandidates',
reg: /^remote-candidates:(.*)/,
format: 'remote-candidates:%s'
},
{
// a=ice-options:google-ice
name: 'iceOptions',
reg: /^ice-options:(\S*)/,
format: 'ice-options:%s'
},
{
// a=ssrc:2566107569 cname:t9YU8M1UxTF8Y1A1
push: 'ssrcs',
reg: /^ssrc:(\d*) ([\w_-]*)(?::(.*))?/,
names: ['id', 'attribute', 'value'],
format: function (o) {
var str = 'ssrc:%d';
if (o.attribute != null) {
str += ' %s';
if (o.value != null) {
str += ':%s';
}
}
return str;
}
},
{
// a=ssrc-group:FEC 1 2
// a=ssrc-group:FEC-FR 3004364195 1080772241
push: 'ssrcGroups',
// token-char = %x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39 / %x41-5A / %x5E-7E
reg: /^ssrc-group:([\x21\x23\x24\x25\x26\x27\x2A\x2B\x2D\x2E\w]*) (.*)/,
names: ['semantics', 'ssrcs'],
format: 'ssrc-group:%s %s'
},
{
// a=msid-semantic: WMS Jvlam5X3SX1OP6pn20zWogvaKJz5Hjf9OnlV
name: 'msidSemantic',
reg: /^msid-semantic:\s?(\w*) (\S*)/,
names: ['semantic', 'token'],
format: 'msid-semantic: %s %s' // space after ':' is not accidental
},
{
// a=group:BUNDLE audio video
push: 'groups',
reg: /^group:(\w*) (.*)/,
names: ['type', 'mids'],
format: 'group:%s %s'
},
{
// a=rtcp-mux
name: 'rtcpMux',
reg: /^(rtcp-mux)/
},
{
// a=rtcp-rsize
name: 'rtcpRsize',
reg: /^(rtcp-rsize)/
},
{
// a=sctpmap:5000 webrtc-datachannel 1024
name: 'sctpmap',
reg: /^sctpmap:([\w_/]*) (\S*)(?: (\S*))?/,
names: ['sctpmapNumber', 'app', 'maxMessageSize'],
format: function (o) {
return (o.maxMessageSize != null)
? 'sctpmap:%s %s %s'
: 'sctpmap:%s %s';
}
},
{
// a=x-google-flag:conference
name: 'xGoogleFlag',
reg: /^x-google-flag:([^\s]*)/,
format: 'x-google-flag:%s'
},
{
// a=rid:1 send max-width=1280;max-height=720;max-fps=30;depend=0
push: 'rids',
reg: /^rid:([\d\w]+) (\w+)(?: ([\S| ]*))?/,
names: ['id', 'direction', 'params'],
format: function (o) {
return (o.params) ? 'rid:%s %s %s' : 'rid:%s %s';
}
},
{
// a=imageattr:97 send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320] recv [x=330,y=250]
// a=imageattr:* send [x=800,y=640] recv *
// a=imageattr:100 recv [x=320,y=240]
push: 'imageattrs',
reg: new RegExp(
// a=imageattr:97
'^imageattr:(\\d+|\\*)' +
// send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320]
'[\\s\\t]+(send|recv)[\\s\\t]+(\\*|\\[\\S+\\](?:[\\s\\t]+\\[\\S+\\])*)' +
// recv [x=330,y=250]
'(?:[\\s\\t]+(recv|send)[\\s\\t]+(\\*|\\[\\S+\\](?:[\\s\\t]+\\[\\S+\\])*))?'
),
names: ['pt', 'dir1', 'attrs1', 'dir2', 'attrs2'],
format: function (o) {
return 'imageattr:%s %s %s' + (o.dir2 ? ' %s %s' : '');
}
},
{
// a=simulcast:send 1,2,3;~4,~5 recv 6;~7,~8
// a=simulcast:recv 1;4,5 send 6;7
name: 'simulcast',
reg: new RegExp(
// a=simulcast:
'^simulcast:' +
// send 1,2,3;~4,~5
'(send|recv) ([a-zA-Z0-9\\-_~;,]+)' +
// space + recv 6;~7,~8
'(?:\\s?(send|recv) ([a-zA-Z0-9\\-_~;,]+))?' +
// end
'$'
),
names: ['dir1', 'list1', 'dir2', 'list2'],
format: function (o) {
return 'simulcast:%s %s' + (o.dir2 ? ' %s %s' : '');
}
},
{
// old simulcast draft 03 (implemented by Firefox)
// https://tools.ietf.org/html/draft-ietf-mmusic-sdp-simulcast-03
// a=simulcast: recv pt=97;98 send pt=97
// a=simulcast: send rid=5;6;7 paused=6,7
name: 'simulcast_03',
reg: /^simulcast:[\s\t]+([\S+\s\t]+)$/,
names: ['value'],
format: 'simulcast: %s'
},
{
// a=framerate:25
// a=framerate:29.97
name: 'framerate',
reg: /^framerate:(\d+(?:$|\.\d+))/,
format: 'framerate:%s'
},
{
// RFC4570
// a=source-filter: incl IN IP4 239.5.2.31 10.1.15.5
name: 'sourceFilter',
reg: /^source-filter: *(excl|incl) (\S*) (IP4|IP6|\*) (\S*) (.*)/,
names: ['filterMode', 'netType', 'addressTypes', 'destAddress', 'srcList'],
format: 'source-filter: %s %s %s %s %s'
},
{
// a=bundle-only
name: 'bundleOnly',
reg: /^(bundle-only)/
},
{
// a=label:1
name: 'label',
reg: /^label:(.+)/,
format: 'label:%s'
},
{
// RFC version 26 for SCTP over DTLS
// https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-5
name: 'sctpPort',
reg: /^sctp-port:(\d+)$/,
format: 'sctp-port:%s'
},
{
// RFC version 26 for SCTP over DTLS
// https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-6
name: 'maxMessageSize',
reg: /^max-message-size:(\d+)$/,
format: 'max-message-size:%s'
},
{
// RFC7273
// a=ts-refclk:ptp=IEEE1588-2008:39-A7-94-FF-FE-07-CB-D0:37
push:'tsRefClocks',
reg: /^ts-refclk:([^\s=]*)(?:=(\S*))?/,
names: ['clksrc', 'clksrcExt'],
format: function (o) {
return 'ts-refclk:%s' + (o.clksrcExt != null ? '=%s' : '');
}
},
{
// RFC7273
// a=mediaclk:direct=963214424
name:'mediaClk',
reg: /^mediaclk:(?:id=(\S*))? *([^\s=]*)(?:=(\S*))?(?: *rate=(\d+)\/(\d+))?/,
names: ['id', 'mediaClockName', 'mediaClockValue', 'rateNumerator', 'rateDenominator'],
format: function (o) {
var str = 'mediaclk:';
str += (o.id != null ? 'id=%s %s' : '%v%s');
str += (o.mediaClockValue != null ? '=%s' : '');
str += (o.rateNumerator != null ? ' rate=%s' : '');
str += (o.rateDenominator != null ? '/%s' : '');
return str;
}
},
{
// a=keywds:keywords
name: 'keywords',
reg: /^keywds:(.+)$/,
format: 'keywds:%s'
},
{
// a=content:main
name: 'content',
reg: /^content:(.+)/,
format: 'content:%s'
},
// BFCP https://tools.ietf.org/html/rfc4583
{
// a=floorctrl:c-s
name: 'bfcpFloorCtrl',
reg: /^floorctrl:(c-only|s-only|c-s)/,
format: 'floorctrl:%s'
},
{
// a=confid:1
name: 'bfcpConfId',
reg: /^confid:(\d+)/,
format: 'confid:%s'
},
{
// a=userid:1
name: 'bfcpUserId',
reg: /^userid:(\d+)/,
format: 'userid:%s'
},
{
// a=floorid:1
name: 'bfcpFloorId',
reg: /^floorid:(.+) (?:m-stream|mstrm):(.+)/,
names: ['id', 'mStream'],
format: 'floorid:%s mstrm:%s'
},
{
// any a= that we don't understand is kept verbatim on media.invalid
push: 'invalid',
names: ['value']
}
]
};
// set sensible defaults to avoid polluting the grammar with boring details
Object.keys(grammar).forEach(function (key) {
var objs = grammar[key];
objs.forEach(function (obj) {
if (!obj.reg) {
obj.reg = /(.*)/;
}
if (!obj.format) {
obj.format = '%s';
}
});
});

13
node_modules/sdp-transform/lib/index.js generated vendored Normal file
View File

@@ -0,0 +1,13 @@
var parser = require('./parser');
var writer = require('./writer');
var grammar = require('./grammar');
exports.grammar = grammar;
exports.write = writer;
exports.parse = parser.parse;
exports.parseParams = parser.parseParams;
exports.parseFmtpConfig = parser.parseFmtpConfig; // Alias of parseParams().
exports.parsePayloads = parser.parsePayloads;
exports.parseRemoteCandidates = parser.parseRemoteCandidates;
exports.parseImageAttributes = parser.parseImageAttributes;
exports.parseSimulcastStreamList = parser.parseSimulcastStreamList;

124
node_modules/sdp-transform/lib/parser.js generated vendored Normal file
View File

@@ -0,0 +1,124 @@
var toIntIfInt = function (v) {
return String(Number(v)) === v ? Number(v) : v;
};
var attachProperties = function (match, location, names, rawName) {
if (rawName && !names) {
location[rawName] = toIntIfInt(match[1]);
}
else {
for (var i = 0; i < names.length; i += 1) {
if (match[i+1] != null) {
location[names[i]] = toIntIfInt(match[i+1]);
}
}
}
};
var parseReg = function (obj, location, content) {
var needsBlank = obj.name && obj.names;
if (obj.push && !location[obj.push]) {
location[obj.push] = [];
}
else if (needsBlank && !location[obj.name]) {
location[obj.name] = {};
}
var keyLocation = obj.push ?
{} : // blank object that will be pushed
needsBlank ? location[obj.name] : location; // otherwise, named location or root
attachProperties(content.match(obj.reg), keyLocation, obj.names, obj.name);
if (obj.push) {
location[obj.push].push(keyLocation);
}
};
var grammar = require('./grammar');
var validLine = RegExp.prototype.test.bind(/^([a-z])=(.*)/);
exports.parse = function (sdp) {
var session = {}
, media = []
, location = session; // points at where properties go under (one of the above)
// parse lines we understand
sdp.split(/(\r\n|\r|\n)/).filter(validLine).forEach(function (l) {
var type = l[0];
var content = l.slice(2);
if (type === 'm') {
media.push({rtp: [], fmtp: []});
location = media[media.length-1]; // point at latest media line
}
for (var j = 0; j < (grammar[type] || []).length; j += 1) {
var obj = grammar[type][j];
if (obj.reg.test(content)) {
return parseReg(obj, location, content);
}
}
});
session.media = media; // link it up
return session;
};
var paramReducer = function (acc, expr) {
var s = expr.split(/=(.+)/, 2);
if (s.length === 2) {
acc[s[0]] = toIntIfInt(s[1]);
} else if (s.length === 1 && expr.length > 1) {
acc[s[0]] = undefined;
}
return acc;
};
exports.parseParams = function (str) {
return str.split(/;\s?/).reduce(paramReducer, {});
};
// For backward compatibility - alias will be removed in 3.0.0
exports.parseFmtpConfig = exports.parseParams;
exports.parsePayloads = function (str) {
return str.toString().split(' ').map(Number);
};
exports.parseRemoteCandidates = function (str) {
var candidates = [];
var parts = str.split(' ').map(toIntIfInt);
for (var i = 0; i < parts.length; i += 3) {
candidates.push({
component: parts[i],
ip: parts[i + 1],
port: parts[i + 2]
});
}
return candidates;
};
exports.parseImageAttributes = function (str) {
return str.split(' ').map(function (item) {
return item.substring(1, item.length-1).split(',').reduce(paramReducer, {});
});
};
exports.parseSimulcastStreamList = function (str) {
return str.split(';').map(function (stream) {
return stream.split(',').map(function (format) {
var scid, paused = false;
if (format[0] !== '~') {
scid = toIntIfInt(format);
} else {
scid = toIntIfInt(format.substring(1, format.length));
paused = true;
}
return {
scid: scid,
paused: paused
};
});
});
};

114
node_modules/sdp-transform/lib/writer.js generated vendored Normal file
View File

@@ -0,0 +1,114 @@
var grammar = require('./grammar');
// customized util.format - discards excess arguments and can void middle ones
var formatRegExp = /%[sdv%]/g;
var format = function (formatStr) {
var i = 1;
var args = arguments;
var len = args.length;
return formatStr.replace(formatRegExp, function (x) {
if (i >= len) {
return x; // missing argument
}
var arg = args[i];
i += 1;
switch (x) {
case '%%':
return '%';
case '%s':
return String(arg);
case '%d':
return Number(arg);
case '%v':
return '';
}
});
// NB: we discard excess arguments - they are typically undefined from makeLine
};
var makeLine = function (type, obj, location) {
var str = obj.format instanceof Function ?
(obj.format(obj.push ? location : location[obj.name])) :
obj.format;
var args = [type + '=' + str];
if (obj.names) {
for (var i = 0; i < obj.names.length; i += 1) {
var n = obj.names[i];
if (obj.name) {
args.push(location[obj.name][n]);
}
else { // for mLine and push attributes
args.push(location[obj.names[i]]);
}
}
}
else {
args.push(location[obj.name]);
}
return format.apply(null, args);
};
// RFC specified order
// TODO: extend this with all the rest
var defaultOuterOrder = [
'v', 'o', 's', 'i',
'u', 'e', 'p', 'c',
'b', 't', 'r', 'z', 'a'
];
var defaultInnerOrder = ['i', 'c', 'b', 'a'];
module.exports = function (session, opts) {
opts = opts || {};
// ensure certain properties exist
if (session.version == null) {
session.version = 0; // 'v=0' must be there (only defined version atm)
}
if (session.name == null) {
session.name = ' '; // 's= ' must be there if no meaningful name set
}
session.media.forEach(function (mLine) {
if (mLine.payloads == null) {
mLine.payloads = '';
}
});
var outerOrder = opts.outerOrder || defaultOuterOrder;
var innerOrder = opts.innerOrder || defaultInnerOrder;
var sdp = [];
// loop through outerOrder for matching properties on session
outerOrder.forEach(function (type) {
grammar[type].forEach(function (obj) {
if (obj.name in session && session[obj.name] != null) {
sdp.push(makeLine(type, obj, session));
}
else if (obj.push in session && session[obj.push] != null) {
session[obj.push].forEach(function (el) {
sdp.push(makeLine(type, obj, el));
});
}
});
});
// then for each media line, follow the innerOrder
session.media.forEach(function (mLine) {
sdp.push(makeLine('m', grammar.m[0], mLine));
innerOrder.forEach(function (type) {
grammar[type].forEach(function (obj) {
if (obj.name in mLine && mLine[obj.name] != null) {
sdp.push(makeLine(type, obj, mLine));
}
else if (obj.push in mLine && mLine[obj.push] != null) {
mLine[obj.push].forEach(function (el) {
sdp.push(makeLine(type, obj, el));
});
}
});
});
});
return sdp.join('\r\n') + '\r\n';
};

34
node_modules/sdp-transform/package.json generated vendored Normal file
View File

@@ -0,0 +1,34 @@
{
"name": "sdp-transform",
"description": "A simple parser/writer for the Session Description Protocol",
"author": "Eirik Albrigtsen <sszynrae@gmail.com>",
"version": "3.0.0",
"repository": {
"type": "git",
"url": "clux/sdp-transform"
},
"keywords": [
"sdp",
"webrtc",
"serializer"
],
"main": "./lib/",
"bin": {
"sdp-verify": "./checker.js"
},
"scripts": {
"lint": "eslint .",
"test": "bndg test/*.test.js",
"coverage": "nyc --reporter=lcov npm run test"
},
"devDependencies": {
"bandage": "^0.5.0",
"co-fs": "^1.2.0",
"eslint": "^5.10.0",
"nyc": "^15.1.0"
},
"bugs": {
"url": "https://github.com/clux/sdp-transform/issues"
},
"license": "MIT"
}