diff options
author | RaindropsSys <contact@minteck.org> | 2023-04-24 14:03:36 +0200 |
---|---|---|
committer | RaindropsSys <contact@minteck.org> | 2023-04-24 14:03:36 +0200 |
commit | 633c92eae865e957121e08de634aeee11a8b3992 (patch) | |
tree | 09d881bee1dae0b6eee49db1dfaf0f500240606c /includes/external/matrix/node_modules/sdp-transform/lib | |
parent | c4657e4509733699c0f26a3c900bab47e915d5a0 (diff) | |
download | pluralconnect-633c92eae865e957121e08de634aeee11a8b3992.tar.gz pluralconnect-633c92eae865e957121e08de634aeee11a8b3992.tar.bz2 pluralconnect-633c92eae865e957121e08de634aeee11a8b3992.zip |
Updated 18 files, added 1692 files and deleted includes/system/compare.inc (automated)
Diffstat (limited to 'includes/external/matrix/node_modules/sdp-transform/lib')
4 files changed, 743 insertions, 0 deletions
diff --git a/includes/external/matrix/node_modules/sdp-transform/lib/grammar.js b/includes/external/matrix/node_modules/sdp-transform/lib/grammar.js new file mode 100644 index 0000000..d8178e8 --- /dev/null +++ b/includes/external/matrix/node_modules/sdp-transform/lib/grammar.js @@ -0,0 +1,494 @@ +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 + name: 'msid', + reg: /^msid:(.*)/, + format: 'msid:%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'; + } + }); +}); diff --git a/includes/external/matrix/node_modules/sdp-transform/lib/index.js b/includes/external/matrix/node_modules/sdp-transform/lib/index.js new file mode 100644 index 0000000..0a27894 --- /dev/null +++ b/includes/external/matrix/node_modules/sdp-transform/lib/index.js @@ -0,0 +1,11 @@ +var parser = require('./parser'); +var writer = require('./writer'); + +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; diff --git a/includes/external/matrix/node_modules/sdp-transform/lib/parser.js b/includes/external/matrix/node_modules/sdp-transform/lib/parser.js new file mode 100644 index 0000000..ac86397 --- /dev/null +++ b/includes/external/matrix/node_modules/sdp-transform/lib/parser.js @@ -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 + }; + }); + }); +}; diff --git a/includes/external/matrix/node_modules/sdp-transform/lib/writer.js b/includes/external/matrix/node_modules/sdp-transform/lib/writer.js new file mode 100644 index 0000000..decdf48 --- /dev/null +++ b/includes/external/matrix/node_modules/sdp-transform/lib/writer.js @@ -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'; +}; |