Без опису
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. var grammar = module.exports = {
  2. v: [{
  3. name: 'version',
  4. reg: /^(\d*)$/
  5. }],
  6. o: [{
  7. // o=- 20518 0 IN IP4 203.0.113.1
  8. // NB: sessionId will be a String in most cases because it is huge
  9. name: 'origin',
  10. reg: /^(\S*) (\d*) (\d*) (\S*) IP(\d) (\S*)/,
  11. names: ['username', 'sessionId', 'sessionVersion', 'netType', 'ipVer', 'address'],
  12. format: '%s %s %d %s IP%d %s'
  13. }],
  14. // default parsing of these only (though some of these feel outdated)
  15. s: [{ name: 'name' }],
  16. i: [{ name: 'description' }],
  17. u: [{ name: 'uri' }],
  18. e: [{ name: 'email' }],
  19. p: [{ name: 'phone' }],
  20. z: [{ name: 'timezones' }], // TODO: this one can actually be parsed properly...
  21. r: [{ name: 'repeats' }], // TODO: this one can also be parsed properly
  22. // k: [{}], // outdated thing ignored
  23. t: [{
  24. // t=0 0
  25. name: 'timing',
  26. reg: /^(\d*) (\d*)/,
  27. names: ['start', 'stop'],
  28. format: '%d %d'
  29. }],
  30. c: [{
  31. // c=IN IP4 10.47.197.26
  32. name: 'connection',
  33. reg: /^IN IP(\d) (\S*)/,
  34. names: ['version', 'ip'],
  35. format: 'IN IP%d %s'
  36. }],
  37. b: [{
  38. // b=AS:4000
  39. push: 'bandwidth',
  40. reg: /^(TIAS|AS|CT|RR|RS):(\d*)/,
  41. names: ['type', 'limit'],
  42. format: '%s:%s'
  43. }],
  44. m: [{
  45. // m=video 51744 RTP/AVP 126 97 98 34 31
  46. // NB: special - pushes to session
  47. // TODO: rtp/fmtp should be filtered by the payloads found here?
  48. reg: /^(\w*) (\d*) ([\w/]*)(?: (.*))?/,
  49. names: ['type', 'port', 'protocol', 'payloads'],
  50. format: '%s %d %s %s'
  51. }],
  52. a: [
  53. {
  54. // a=rtpmap:110 opus/48000/2
  55. push: 'rtp',
  56. reg: /^rtpmap:(\d*) ([\w\-.]*)(?:\s*\/(\d*)(?:\s*\/(\S*))?)?/,
  57. names: ['payload', 'codec', 'rate', 'encoding'],
  58. format: function (o) {
  59. return (o.encoding)
  60. ? 'rtpmap:%d %s/%s/%s'
  61. : o.rate
  62. ? 'rtpmap:%d %s/%s'
  63. : 'rtpmap:%d %s';
  64. }
  65. },
  66. {
  67. // a=fmtp:108 profile-level-id=24;object=23;bitrate=64000
  68. // a=fmtp:111 minptime=10; useinbandfec=1
  69. push: 'fmtp',
  70. reg: /^fmtp:(\d*) ([\S| ]*)/,
  71. names: ['payload', 'config'],
  72. format: 'fmtp:%d %s'
  73. },
  74. {
  75. // a=control:streamid=0
  76. name: 'control',
  77. reg: /^control:(.*)/,
  78. format: 'control:%s'
  79. },
  80. {
  81. // a=rtcp:65179 IN IP4 193.84.77.194
  82. name: 'rtcp',
  83. reg: /^rtcp:(\d*)(?: (\S*) IP(\d) (\S*))?/,
  84. names: ['port', 'netType', 'ipVer', 'address'],
  85. format: function (o) {
  86. return (o.address != null)
  87. ? 'rtcp:%d %s IP%d %s'
  88. : 'rtcp:%d';
  89. }
  90. },
  91. {
  92. // a=rtcp-fb:98 trr-int 100
  93. push: 'rtcpFbTrrInt',
  94. reg: /^rtcp-fb:(\*|\d*) trr-int (\d*)/,
  95. names: ['payload', 'value'],
  96. format: 'rtcp-fb:%d trr-int %d'
  97. },
  98. {
  99. // a=rtcp-fb:98 nack rpsi
  100. push: 'rtcpFb',
  101. reg: /^rtcp-fb:(\*|\d*) ([\w-_]*)(?: ([\w-_]*))?/,
  102. names: ['payload', 'type', 'subtype'],
  103. format: function (o) {
  104. return (o.subtype != null)
  105. ? 'rtcp-fb:%s %s %s'
  106. : 'rtcp-fb:%s %s';
  107. }
  108. },
  109. {
  110. // a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
  111. // a=extmap:1/recvonly URI-gps-string
  112. // a=extmap:3 urn:ietf:params:rtp-hdrext:encrypt urn:ietf:params:rtp-hdrext:smpte-tc 25@600/24
  113. push: 'ext',
  114. reg: /^extmap:(\d+)(?:\/(\w+))?(?: (urn:ietf:params:rtp-hdrext:encrypt))? (\S*)(?: (\S*))?/,
  115. names: ['value', 'direction', 'encrypt-uri', 'uri', 'config'],
  116. format: function (o) {
  117. return (
  118. 'extmap:%d' +
  119. (o.direction ? '/%s' : '%v') +
  120. (o['encrypt-uri'] ? ' %s' : '%v') +
  121. ' %s' +
  122. (o.config ? ' %s' : '')
  123. );
  124. }
  125. },
  126. {
  127. // a=extmap-allow-mixed
  128. name: 'extmapAllowMixed',
  129. reg: /^(extmap-allow-mixed)/
  130. },
  131. {
  132. // a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR|2^20|1:32
  133. push: 'crypto',
  134. reg: /^crypto:(\d*) ([\w_]*) (\S*)(?: (\S*))?/,
  135. names: ['id', 'suite', 'config', 'sessionConfig'],
  136. format: function (o) {
  137. return (o.sessionConfig != null)
  138. ? 'crypto:%d %s %s %s'
  139. : 'crypto:%d %s %s';
  140. }
  141. },
  142. {
  143. // a=setup:actpass
  144. name: 'setup',
  145. reg: /^setup:(\w*)/,
  146. format: 'setup:%s'
  147. },
  148. {
  149. // a=connection:new
  150. name: 'connectionType',
  151. reg: /^connection:(new|existing)/,
  152. format: 'connection:%s'
  153. },
  154. {
  155. // a=mid:1
  156. name: 'mid',
  157. reg: /^mid:([^\s]*)/,
  158. format: 'mid:%s'
  159. },
  160. {
  161. // a=msid:0c8b064d-d807-43b4-b434-f92a889d8587 98178685-d409-46e0-8e16-7ef0db0db64a
  162. name: 'msid',
  163. reg: /^msid:(.*)/,
  164. format: 'msid:%s'
  165. },
  166. {
  167. // a=ptime:20
  168. name: 'ptime',
  169. reg: /^ptime:(\d*(?:\.\d*)*)/,
  170. format: 'ptime:%d'
  171. },
  172. {
  173. // a=maxptime:60
  174. name: 'maxptime',
  175. reg: /^maxptime:(\d*(?:\.\d*)*)/,
  176. format: 'maxptime:%d'
  177. },
  178. {
  179. // a=sendrecv
  180. name: 'direction',
  181. reg: /^(sendrecv|recvonly|sendonly|inactive)/
  182. },
  183. {
  184. // a=ice-lite
  185. name: 'icelite',
  186. reg: /^(ice-lite)/
  187. },
  188. {
  189. // a=ice-ufrag:F7gI
  190. name: 'iceUfrag',
  191. reg: /^ice-ufrag:(\S*)/,
  192. format: 'ice-ufrag:%s'
  193. },
  194. {
  195. // a=ice-pwd:x9cml/YzichV2+XlhiMu8g
  196. name: 'icePwd',
  197. reg: /^ice-pwd:(\S*)/,
  198. format: 'ice-pwd:%s'
  199. },
  200. {
  201. // a=fingerprint:SHA-1 00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33
  202. name: 'fingerprint',
  203. reg: /^fingerprint:(\S*) (\S*)/,
  204. names: ['type', 'hash'],
  205. format: 'fingerprint:%s %s'
  206. },
  207. {
  208. // a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
  209. // a=candidate:1162875081 1 udp 2113937151 192.168.34.75 60017 typ host generation 0 network-id 3 network-cost 10
  210. // 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
  211. // a=candidate:229815620 1 tcp 1518280447 192.168.150.19 60017 typ host tcptype active generation 0 network-id 3 network-cost 10
  212. // 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
  213. push: 'candidates',
  214. reg: /^candidate:(\S*) (\d*) (\S*) (\d*) (\S*) (\d*) typ (\S*)(?: raddr (\S*) rport (\d*))?(?: tcptype (\S*))?(?: generation (\d*))?(?: network-id (\d*))?(?: network-cost (\d*))?/,
  215. names: ['foundation', 'component', 'transport', 'priority', 'ip', 'port', 'type', 'raddr', 'rport', 'tcptype', 'generation', 'network-id', 'network-cost'],
  216. format: function (o) {
  217. var str = 'candidate:%s %d %s %d %s %d typ %s';
  218. str += (o.raddr != null) ? ' raddr %s rport %d' : '%v%v';
  219. // NB: candidate has three optional chunks, so %void middles one if it's missing
  220. str += (o.tcptype != null) ? ' tcptype %s' : '%v';
  221. if (o.generation != null) {
  222. str += ' generation %d';
  223. }
  224. str += (o['network-id'] != null) ? ' network-id %d' : '%v';
  225. str += (o['network-cost'] != null) ? ' network-cost %d' : '%v';
  226. return str;
  227. }
  228. },
  229. {
  230. // a=end-of-candidates (keep after the candidates line for readability)
  231. name: 'endOfCandidates',
  232. reg: /^(end-of-candidates)/
  233. },
  234. {
  235. // a=remote-candidates:1 203.0.113.1 54400 2 203.0.113.1 54401 ...
  236. name: 'remoteCandidates',
  237. reg: /^remote-candidates:(.*)/,
  238. format: 'remote-candidates:%s'
  239. },
  240. {
  241. // a=ice-options:google-ice
  242. name: 'iceOptions',
  243. reg: /^ice-options:(\S*)/,
  244. format: 'ice-options:%s'
  245. },
  246. {
  247. // a=ssrc:2566107569 cname:t9YU8M1UxTF8Y1A1
  248. push: 'ssrcs',
  249. reg: /^ssrc:(\d*) ([\w_-]*)(?::(.*))?/,
  250. names: ['id', 'attribute', 'value'],
  251. format: function (o) {
  252. var str = 'ssrc:%d';
  253. if (o.attribute != null) {
  254. str += ' %s';
  255. if (o.value != null) {
  256. str += ':%s';
  257. }
  258. }
  259. return str;
  260. }
  261. },
  262. {
  263. // a=ssrc-group:FEC 1 2
  264. // a=ssrc-group:FEC-FR 3004364195 1080772241
  265. push: 'ssrcGroups',
  266. // token-char = %x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39 / %x41-5A / %x5E-7E
  267. reg: /^ssrc-group:([\x21\x23\x24\x25\x26\x27\x2A\x2B\x2D\x2E\w]*) (.*)/,
  268. names: ['semantics', 'ssrcs'],
  269. format: 'ssrc-group:%s %s'
  270. },
  271. {
  272. // a=msid-semantic: WMS Jvlam5X3SX1OP6pn20zWogvaKJz5Hjf9OnlV
  273. name: 'msidSemantic',
  274. reg: /^msid-semantic:\s?(\w*) (\S*)/,
  275. names: ['semantic', 'token'],
  276. format: 'msid-semantic: %s %s' // space after ':' is not accidental
  277. },
  278. {
  279. // a=group:BUNDLE audio video
  280. push: 'groups',
  281. reg: /^group:(\w*) (.*)/,
  282. names: ['type', 'mids'],
  283. format: 'group:%s %s'
  284. },
  285. {
  286. // a=rtcp-mux
  287. name: 'rtcpMux',
  288. reg: /^(rtcp-mux)/
  289. },
  290. {
  291. // a=rtcp-rsize
  292. name: 'rtcpRsize',
  293. reg: /^(rtcp-rsize)/
  294. },
  295. {
  296. // a=sctpmap:5000 webrtc-datachannel 1024
  297. name: 'sctpmap',
  298. reg: /^sctpmap:([\w_/]*) (\S*)(?: (\S*))?/,
  299. names: ['sctpmapNumber', 'app', 'maxMessageSize'],
  300. format: function (o) {
  301. return (o.maxMessageSize != null)
  302. ? 'sctpmap:%s %s %s'
  303. : 'sctpmap:%s %s';
  304. }
  305. },
  306. {
  307. // a=x-google-flag:conference
  308. name: 'xGoogleFlag',
  309. reg: /^x-google-flag:([^\s]*)/,
  310. format: 'x-google-flag:%s'
  311. },
  312. {
  313. // a=rid:1 send max-width=1280;max-height=720;max-fps=30;depend=0
  314. push: 'rids',
  315. reg: /^rid:([\d\w]+) (\w+)(?: ([\S| ]*))?/,
  316. names: ['id', 'direction', 'params'],
  317. format: function (o) {
  318. return (o.params) ? 'rid:%s %s %s' : 'rid:%s %s';
  319. }
  320. },
  321. {
  322. // a=imageattr:97 send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320] recv [x=330,y=250]
  323. // a=imageattr:* send [x=800,y=640] recv *
  324. // a=imageattr:100 recv [x=320,y=240]
  325. push: 'imageattrs',
  326. reg: new RegExp(
  327. // a=imageattr:97
  328. '^imageattr:(\\d+|\\*)' +
  329. // send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320]
  330. '[\\s\\t]+(send|recv)[\\s\\t]+(\\*|\\[\\S+\\](?:[\\s\\t]+\\[\\S+\\])*)' +
  331. // recv [x=330,y=250]
  332. '(?:[\\s\\t]+(recv|send)[\\s\\t]+(\\*|\\[\\S+\\](?:[\\s\\t]+\\[\\S+\\])*))?'
  333. ),
  334. names: ['pt', 'dir1', 'attrs1', 'dir2', 'attrs2'],
  335. format: function (o) {
  336. return 'imageattr:%s %s %s' + (o.dir2 ? ' %s %s' : '');
  337. }
  338. },
  339. {
  340. // a=simulcast:send 1,2,3;~4,~5 recv 6;~7,~8
  341. // a=simulcast:recv 1;4,5 send 6;7
  342. name: 'simulcast',
  343. reg: new RegExp(
  344. // a=simulcast:
  345. '^simulcast:' +
  346. // send 1,2,3;~4,~5
  347. '(send|recv) ([a-zA-Z0-9\\-_~;,]+)' +
  348. // space + recv 6;~7,~8
  349. '(?:\\s?(send|recv) ([a-zA-Z0-9\\-_~;,]+))?' +
  350. // end
  351. '$'
  352. ),
  353. names: ['dir1', 'list1', 'dir2', 'list2'],
  354. format: function (o) {
  355. return 'simulcast:%s %s' + (o.dir2 ? ' %s %s' : '');
  356. }
  357. },
  358. {
  359. // old simulcast draft 03 (implemented by Firefox)
  360. // https://tools.ietf.org/html/draft-ietf-mmusic-sdp-simulcast-03
  361. // a=simulcast: recv pt=97;98 send pt=97
  362. // a=simulcast: send rid=5;6;7 paused=6,7
  363. name: 'simulcast_03',
  364. reg: /^simulcast:[\s\t]+([\S+\s\t]+)$/,
  365. names: ['value'],
  366. format: 'simulcast: %s'
  367. },
  368. {
  369. // a=framerate:25
  370. // a=framerate:29.97
  371. name: 'framerate',
  372. reg: /^framerate:(\d+(?:$|\.\d+))/,
  373. format: 'framerate:%s'
  374. },
  375. {
  376. // RFC4570
  377. // a=source-filter: incl IN IP4 239.5.2.31 10.1.15.5
  378. name: 'sourceFilter',
  379. reg: /^source-filter: *(excl|incl) (\S*) (IP4|IP6|\*) (\S*) (.*)/,
  380. names: ['filterMode', 'netType', 'addressTypes', 'destAddress', 'srcList'],
  381. format: 'source-filter: %s %s %s %s %s'
  382. },
  383. {
  384. // a=bundle-only
  385. name: 'bundleOnly',
  386. reg: /^(bundle-only)/
  387. },
  388. {
  389. // a=label:1
  390. name: 'label',
  391. reg: /^label:(.+)/,
  392. format: 'label:%s'
  393. },
  394. {
  395. // RFC version 26 for SCTP over DTLS
  396. // https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-5
  397. name: 'sctpPort',
  398. reg: /^sctp-port:(\d+)$/,
  399. format: 'sctp-port:%s'
  400. },
  401. {
  402. // RFC version 26 for SCTP over DTLS
  403. // https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-6
  404. name: 'maxMessageSize',
  405. reg: /^max-message-size:(\d+)$/,
  406. format: 'max-message-size:%s'
  407. },
  408. {
  409. // RFC7273
  410. // a=ts-refclk:ptp=IEEE1588-2008:39-A7-94-FF-FE-07-CB-D0:37
  411. push: 'tsRefClocks',
  412. reg: /^ts-refclk:([^\s=]*)(?:=(\S*))?/,
  413. names: ['clksrc', 'clksrcExt'],
  414. format: function (o) {
  415. return 'ts-refclk:%s' + (o.clksrcExt != null ? '=%s' : '');
  416. }
  417. },
  418. {
  419. // RFC7273
  420. // a=mediaclk:direct=963214424
  421. name: 'mediaClk',
  422. reg: /^mediaclk:(?:id=(\S*))? *([^\s=]*)(?:=(\S*))?(?: *rate=(\d+)\/(\d+))?/,
  423. names: ['id', 'mediaClockName', 'mediaClockValue', 'rateNumerator', 'rateDenominator'],
  424. format: function (o) {
  425. var str = 'mediaclk:';
  426. str += (o.id != null ? 'id=%s %s' : '%v%s');
  427. str += (o.mediaClockValue != null ? '=%s' : '');
  428. str += (o.rateNumerator != null ? ' rate=%s' : '');
  429. str += (o.rateDenominator != null ? '/%s' : '');
  430. return str;
  431. }
  432. },
  433. {
  434. // a=keywds:keywords
  435. name: 'keywords',
  436. reg: /^keywds:(.+)$/,
  437. format: 'keywds:%s'
  438. },
  439. {
  440. // a=content:main
  441. name: 'content',
  442. reg: /^content:(.+)/,
  443. format: 'content:%s'
  444. },
  445. // BFCP https://tools.ietf.org/html/rfc4583
  446. {
  447. // a=floorctrl:c-s
  448. name: 'bfcpFloorCtrl',
  449. reg: /^floorctrl:(c-only|s-only|c-s)/,
  450. format: 'floorctrl:%s'
  451. },
  452. {
  453. // a=confid:1
  454. name: 'bfcpConfId',
  455. reg: /^confid:(\d+)/,
  456. format: 'confid:%s'
  457. },
  458. {
  459. // a=userid:1
  460. name: 'bfcpUserId',
  461. reg: /^userid:(\d+)/,
  462. format: 'userid:%s'
  463. },
  464. {
  465. // a=floorid:1
  466. name: 'bfcpFloorId',
  467. reg: /^floorid:(.+) (?:m-stream|mstrm):(.+)/,
  468. names: ['id', 'mStream'],
  469. format: 'floorid:%s mstrm:%s'
  470. },
  471. {
  472. // any a= that we don't understand is kept verbatim on media.invalid
  473. push: 'invalid',
  474. names: ['value']
  475. }
  476. ],
  477. y: [{ name: 'ssrc' }],
  478. };
  479. // set sensible defaults to avoid polluting the grammar with boring details
  480. Object.keys(grammar).forEach(function (key) {
  481. var objs = grammar[key];
  482. objs.forEach(function (obj) {
  483. if (!obj.reg) {
  484. obj.reg = /(.*)/;
  485. }
  486. if (!obj.format) {
  487. obj.format = '%s';
  488. }
  489. });
  490. });