Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

SDPUtil.js 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. SDPUtil = {
  2. iceparams: function (mediadesc, sessiondesc) {
  3. var data = null;
  4. if (SDPUtil.find_line(mediadesc, 'a=ice-ufrag:', sessiondesc) &&
  5. SDPUtil.find_line(mediadesc, 'a=ice-pwd:', sessiondesc)) {
  6. data = {
  7. ufrag: SDPUtil.parse_iceufrag(SDPUtil.find_line(mediadesc, 'a=ice-ufrag:', sessiondesc)),
  8. pwd: SDPUtil.parse_icepwd(SDPUtil.find_line(mediadesc, 'a=ice-pwd:', sessiondesc))
  9. };
  10. }
  11. return data;
  12. },
  13. parse_iceufrag: function (line) {
  14. return line.substring(12);
  15. },
  16. build_iceufrag: function (frag) {
  17. return 'a=ice-ufrag:' + frag;
  18. },
  19. parse_icepwd: function (line) {
  20. return line.substring(10);
  21. },
  22. build_icepwd: function (pwd) {
  23. return 'a=ice-pwd:' + pwd;
  24. },
  25. parse_mid: function (line) {
  26. return line.substring(6);
  27. },
  28. parse_mline: function (line) {
  29. var parts = line.substring(2).split(' '),
  30. data = {};
  31. data.media = parts.shift();
  32. data.port = parts.shift();
  33. data.proto = parts.shift();
  34. if (parts[parts.length - 1] === '') { // trailing whitespace
  35. parts.pop();
  36. }
  37. data.fmt = parts;
  38. return data;
  39. },
  40. build_mline: function (mline) {
  41. return 'm=' + mline.media + ' ' + mline.port + ' ' + mline.proto + ' ' + mline.fmt.join(' ');
  42. },
  43. parse_rtpmap: function (line) {
  44. var parts = line.substring(9).split(' '),
  45. data = {};
  46. data.id = parts.shift();
  47. parts = parts[0].split('/');
  48. data.name = parts.shift();
  49. data.clockrate = parts.shift();
  50. data.channels = parts.length ? parts.shift() : '1';
  51. return data;
  52. },
  53. /**
  54. * Parses SDP line "a=sctpmap:..." and extracts SCTP port from it.
  55. * @param line eg. "a=sctpmap:5000 webrtc-datachannel"
  56. * @returns [SCTP port number, protocol, streams]
  57. */
  58. parse_sctpmap: function (line)
  59. {
  60. var parts = line.substring(10).split(' ');
  61. var sctpPort = parts[0];
  62. var protocol = parts[1];
  63. // Stream count is optional
  64. var streamCount = parts.length > 2 ? parts[2] : null;
  65. return [sctpPort, protocol, streamCount];// SCTP port
  66. },
  67. build_rtpmap: function (el) {
  68. var line = 'a=rtpmap:' + el.getAttribute('id') + ' ' + el.getAttribute('name') + '/' + el.getAttribute('clockrate');
  69. if (el.getAttribute('channels') && el.getAttribute('channels') != '1') {
  70. line += '/' + el.getAttribute('channels');
  71. }
  72. return line;
  73. },
  74. parse_crypto: function (line) {
  75. var parts = line.substring(9).split(' '),
  76. data = {};
  77. data.tag = parts.shift();
  78. data['crypto-suite'] = parts.shift();
  79. data['key-params'] = parts.shift();
  80. if (parts.length) {
  81. data['session-params'] = parts.join(' ');
  82. }
  83. return data;
  84. },
  85. parse_fingerprint: function (line) { // RFC 4572
  86. var parts = line.substring(14).split(' '),
  87. data = {};
  88. data.hash = parts.shift();
  89. data.fingerprint = parts.shift();
  90. // TODO assert that fingerprint satisfies 2UHEX *(":" 2UHEX) ?
  91. return data;
  92. },
  93. parse_fmtp: function (line) {
  94. var parts = line.split(' '),
  95. i, key, value,
  96. data = [];
  97. parts.shift();
  98. parts = parts.join(' ').split(';');
  99. for (i = 0; i < parts.length; i++) {
  100. key = parts[i].split('=')[0];
  101. while (key.length && key[0] == ' ') {
  102. key = key.substring(1);
  103. }
  104. value = parts[i].split('=')[1];
  105. if (key && value) {
  106. data.push({name: key, value: value});
  107. } else if (key) {
  108. // rfc 4733 (DTMF) style stuff
  109. data.push({name: '', value: key});
  110. }
  111. }
  112. return data;
  113. },
  114. parse_icecandidate: function (line) {
  115. var candidate = {},
  116. elems = line.split(' ');
  117. candidate.foundation = elems[0].substring(12);
  118. candidate.component = elems[1];
  119. candidate.protocol = elems[2].toLowerCase();
  120. candidate.priority = elems[3];
  121. candidate.ip = elems[4];
  122. candidate.port = elems[5];
  123. // elems[6] => "typ"
  124. candidate.type = elems[7];
  125. candidate.generation = 0; // default value, may be overwritten below
  126. for (var i = 8; i < elems.length; i += 2) {
  127. switch (elems[i]) {
  128. case 'raddr':
  129. candidate['rel-addr'] = elems[i + 1];
  130. break;
  131. case 'rport':
  132. candidate['rel-port'] = elems[i + 1];
  133. break;
  134. case 'generation':
  135. candidate.generation = elems[i + 1];
  136. break;
  137. case 'tcptype':
  138. candidate.tcptype = elems[i + 1];
  139. break;
  140. default: // TODO
  141. console.log('parse_icecandidate not translating "' + elems[i] + '" = "' + elems[i + 1] + '"');
  142. }
  143. }
  144. candidate.network = '1';
  145. candidate.id = Math.random().toString(36).substr(2, 10); // not applicable to SDP -- FIXME: should be unique, not just random
  146. return candidate;
  147. },
  148. build_icecandidate: function (cand) {
  149. var line = ['a=candidate:' + cand.foundation, cand.component, cand.protocol, cand.priority, cand.ip, cand.port, 'typ', cand.type].join(' ');
  150. line += ' ';
  151. switch (cand.type) {
  152. case 'srflx':
  153. case 'prflx':
  154. case 'relay':
  155. if (cand.hasOwnAttribute('rel-addr') && cand.hasOwnAttribute('rel-port')) {
  156. line += 'raddr';
  157. line += ' ';
  158. line += cand['rel-addr'];
  159. line += ' ';
  160. line += 'rport';
  161. line += ' ';
  162. line += cand['rel-port'];
  163. line += ' ';
  164. }
  165. break;
  166. }
  167. if (cand.hasOwnAttribute('tcptype')) {
  168. line += 'tcptype';
  169. line += ' ';
  170. line += cand.tcptype;
  171. line += ' ';
  172. }
  173. line += 'generation';
  174. line += ' ';
  175. line += cand.hasOwnAttribute('generation') ? cand.generation : '0';
  176. return line;
  177. },
  178. parse_ssrc: function (desc) {
  179. // proprietary mapping of a=ssrc lines
  180. // TODO: see "Jingle RTP Source Description" by Juberti and P. Thatcher on google docs
  181. // and parse according to that
  182. var lines = desc.split('\r\n'),
  183. data = {};
  184. for (var i = 0; i < lines.length; i++) {
  185. if (lines[i].substring(0, 7) == 'a=ssrc:') {
  186. var idx = lines[i].indexOf(' ');
  187. data[lines[i].substr(idx + 1).split(':', 2)[0]] = lines[i].substr(idx + 1).split(':', 2)[1];
  188. }
  189. }
  190. return data;
  191. },
  192. parse_rtcpfb: function (line) {
  193. var parts = line.substr(10).split(' ');
  194. var data = {};
  195. data.pt = parts.shift();
  196. data.type = parts.shift();
  197. data.params = parts;
  198. return data;
  199. },
  200. parse_extmap: function (line) {
  201. var parts = line.substr(9).split(' ');
  202. var data = {};
  203. data.value = parts.shift();
  204. if (data.value.indexOf('/') != -1) {
  205. data.direction = data.value.substr(data.value.indexOf('/') + 1);
  206. data.value = data.value.substr(0, data.value.indexOf('/'));
  207. } else {
  208. data.direction = 'both';
  209. }
  210. data.uri = parts.shift();
  211. data.params = parts;
  212. return data;
  213. },
  214. find_line: function (haystack, needle, sessionpart) {
  215. var lines = haystack.split('\r\n');
  216. for (var i = 0; i < lines.length; i++) {
  217. if (lines[i].substring(0, needle.length) == needle) {
  218. return lines[i];
  219. }
  220. }
  221. if (!sessionpart) {
  222. return false;
  223. }
  224. // search session part
  225. lines = sessionpart.split('\r\n');
  226. for (var j = 0; j < lines.length; j++) {
  227. if (lines[j].substring(0, needle.length) == needle) {
  228. return lines[j];
  229. }
  230. }
  231. return false;
  232. },
  233. find_lines: function (haystack, needle, sessionpart) {
  234. var lines = haystack.split('\r\n'),
  235. needles = [];
  236. for (var i = 0; i < lines.length; i++) {
  237. if (lines[i].substring(0, needle.length) == needle)
  238. needles.push(lines[i]);
  239. }
  240. if (needles.length || !sessionpart) {
  241. return needles;
  242. }
  243. // search session part
  244. lines = sessionpart.split('\r\n');
  245. for (var j = 0; j < lines.length; j++) {
  246. if (lines[j].substring(0, needle.length) == needle) {
  247. needles.push(lines[j]);
  248. }
  249. }
  250. return needles;
  251. },
  252. candidateToJingle: function (line) {
  253. // a=candidate:2979166662 1 udp 2113937151 192.168.2.100 57698 typ host generation 0
  254. // <candidate component=... foundation=... generation=... id=... ip=... network=... port=... priority=... protocol=... type=.../>
  255. if (line.indexOf('candidate:') === 0) {
  256. line = 'a=' + line;
  257. } else if (line.substring(0, 12) != 'a=candidate:') {
  258. console.log('parseCandidate called with a line that is not a candidate line');
  259. console.log(line);
  260. return null;
  261. }
  262. if (line.substring(line.length - 2) == '\r\n') // chomp it
  263. line = line.substring(0, line.length - 2);
  264. var candidate = {},
  265. elems = line.split(' '),
  266. i;
  267. if (elems[6] != 'typ') {
  268. console.log('did not find typ in the right place');
  269. console.log(line);
  270. return null;
  271. }
  272. candidate.foundation = elems[0].substring(12);
  273. candidate.component = elems[1];
  274. candidate.protocol = elems[2].toLowerCase();
  275. candidate.priority = elems[3];
  276. candidate.ip = elems[4];
  277. candidate.port = elems[5];
  278. // elems[6] => "typ"
  279. candidate.type = elems[7];
  280. candidate.generation = '0'; // default, may be overwritten below
  281. for (i = 8; i < elems.length; i += 2) {
  282. switch (elems[i]) {
  283. case 'raddr':
  284. candidate['rel-addr'] = elems[i + 1];
  285. break;
  286. case 'rport':
  287. candidate['rel-port'] = elems[i + 1];
  288. break;
  289. case 'generation':
  290. candidate.generation = elems[i + 1];
  291. break;
  292. case 'tcptype':
  293. candidate.tcptype = elems[i + 1];
  294. break;
  295. default: // TODO
  296. console.log('not translating "' + elems[i] + '" = "' + elems[i + 1] + '"');
  297. }
  298. }
  299. candidate.network = '1';
  300. candidate.id = Math.random().toString(36).substr(2, 10); // not applicable to SDP -- FIXME: should be unique, not just random
  301. return candidate;
  302. },
  303. candidateFromJingle: function (cand) {
  304. var line = 'a=candidate:';
  305. line += cand.getAttribute('foundation');
  306. line += ' ';
  307. line += cand.getAttribute('component');
  308. line += ' ';
  309. line += cand.getAttribute('protocol'); //.toUpperCase(); // chrome M23 doesn't like this
  310. line += ' ';
  311. line += cand.getAttribute('priority');
  312. line += ' ';
  313. line += cand.getAttribute('ip');
  314. line += ' ';
  315. line += cand.getAttribute('port');
  316. line += ' ';
  317. line += 'typ';
  318. line += ' ' + cand.getAttribute('type');
  319. line += ' ';
  320. switch (cand.getAttribute('type')) {
  321. case 'srflx':
  322. case 'prflx':
  323. case 'relay':
  324. if (cand.getAttribute('rel-addr') && cand.getAttribute('rel-port')) {
  325. line += 'raddr';
  326. line += ' ';
  327. line += cand.getAttribute('rel-addr');
  328. line += ' ';
  329. line += 'rport';
  330. line += ' ';
  331. line += cand.getAttribute('rel-port');
  332. line += ' ';
  333. }
  334. break;
  335. }
  336. if (cand.getAttribute('protocol').toLowerCase() == 'tcp') {
  337. line += 'tcptype';
  338. line += ' ';
  339. line += cand.getAttribute('tcptype');
  340. line += ' ';
  341. }
  342. line += 'generation';
  343. line += ' ';
  344. line += cand.getAttribute('generation') || '0';
  345. return line + '\r\n';
  346. }
  347. };
  348. module.exports = SDPUtil;