Package detail

sdp-transform

clux1.2mMIT2.15.0

A simple parser/writer for the Session Description Protocol

sdp, webrtc, serializer

readme

SDP Transform

npm status CI codecov

A simple parser and writer of SDP. Defines internal grammar based on RFC4566 - SDP, RFC5245 - ICE, 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

$ npm install sdp-transform

TypeScript Definitions

Available in the @types/sdp-transform package:

$ npm install -D @types/sdp-transform

Usage

Load using CommonJS syntax or ES6 syntax:

// CommonJS
const sdpTransform = require('sdp-transform');

// ES6
import * as sdpTransform from 'sdp-transform';

Usage - Parser

Pass it an unprocessed SDP string.

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.

// 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.

// what payloads where actually advertised in the main m-line ?
sdpTransform.parsePayloads(res.media[1].payloads);
// =>
[97, 98]

parseImageAttributes()

Parses Generic Image Attributes. Must be provided with the attrs1 or attrs2 string of a a=imageattr line. Returns an array of key/value objects.

// 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 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
// 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.

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.

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.

changelog

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