You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SDP.spec.js 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /* globals $ */
  2. import { $iq } from 'strophe.js';
  3. import SDP from './SDP';
  4. /**
  5. * @param {string} xml - raw xml of the stanza
  6. */
  7. function createStanzaElement(xml) {
  8. return new DOMParser().parseFromString(xml, 'text/xml').documentElement;
  9. }
  10. describe('SDP', () => {
  11. describe('toJingle', () => {
  12. /* eslint-disable max-len*/
  13. const testSdp = [
  14. 'v=0\r\n',
  15. 'o=thisisadapterortc 2719486166053431 0 IN IP4 127.0.0.1\r\n',
  16. 's=-\r\n',
  17. 't=0 0\r\n',
  18. 'a=group:BUNDLE audio video\r\n',
  19. 'm=audio 9 UDP/TLS/RTP/SAVPF 111 126\r\n',
  20. 'c=IN IP4 0.0.0.0\r\n',
  21. 'a=rtpmap:111 opus/48000/2\r\n',
  22. 'a=rtpmap:126 telephone-event/8000\r\n',
  23. 'a=fmtp:126 0-15\r\n',
  24. 'a=fmtp:111 minptime=10;useinbandfec=1\r\n',
  25. 'a=rtcp:9 IN IP4 0.0.0.0\r\n',
  26. 'a=setup:active\r\n',
  27. 'a=mid:audio\r\n',
  28. 'a=msid:26D16D51-503A-420B-8274-3DD1174E498F 8205D1FC-50B4-407C-87D5-9C45F1B779F0\r\n',
  29. 'a=sendrecv\r\n',
  30. 'a=ice-ufrag:tOQd\r\n',
  31. 'a=ice-pwd:3sAozs7hw6+2O6DBp2pt9fvY\r\n',
  32. 'a=fingerprint:sha-256 A9:00:CC:F9:81:33:EA:E9:E3:B4:01:E9:9E:18:B3:9B:F8:49:25:A0:5D:12:20:70:D5:6F:34:5A:2A:39:19:0A\r\n',
  33. 'a=ssrc:2002 msid:26D16D51-503A-420B-8274-3DD1174E498F 8205D1FC-50B4-407C-87D5-9C45F1B779F0\r\n',
  34. 'a=ssrc:2002 cname:juejgy8a01\r\n',
  35. 'a=rtcp-mux\r\n',
  36. 'm=video 9 UDP/TLS/RTP/SAVPF 107 100 99 96\r\n',
  37. 'c=IN IP4 0.0.0.0\r\n',
  38. 'a=rtpmap:107 h264/90000\r\n',
  39. 'a=rtpmap:100 VP8/90000\r\n',
  40. 'a=rtpmap:99 rtx/90000\r\n',
  41. 'a=rtpmap:96 rtx/90000\r\n',
  42. 'a=fmtp:107 x-google-start-bitrate=800\r\n',
  43. 'a=fmtp:100 x-google-start-bitrate=800\r\n',
  44. 'a=fmtp:99 apt=107\r\n',
  45. 'a=fmtp:96 apt=100\r\n',
  46. 'a=rtcp:9 IN IP4 0.0.0.0\r\n',
  47. 'a=rtcp-fb:107 nack\r\n',
  48. 'a=rtcp-fb:107 nack pli\r\n',
  49. 'a=rtcp-fb:107 goog-remb\r\n',
  50. 'a=rtcp-fb:100 nack\r\n',
  51. 'a=rtcp-fb:100 nack pli\r\n',
  52. 'a=rtcp-fb:100 goog-remb\r\n',
  53. 'a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\n',
  54. 'a=setup:active\r\n',
  55. 'a=mid:video\r\n',
  56. 'a=msid:7C0035E5-2DA1-4AEA-804A-9E75BF9B3768 225E9CDA-0384-4C92-92DD-E74C1153EC68\r\n',
  57. 'a=sendrecv\r\n',
  58. 'a=ice-ufrag:tOQd\r\n',
  59. 'a=ice-pwd:3sAozs7hw6+2O6DBp2pt9fvY\r\n',
  60. 'a=fingerprint:sha-256 A9:00:CC:F9:81:33:EA:E9:E3:B4:01:E9:9E:18:B3:9B:F8:49:25:A0:5D:12:20:70:D5:6F:34:5A:2A:39:19:0A\r\n',
  61. 'a=ssrc:4004 msid:7C0035E5-2DA1-4AEA-804A-9E75BF9B3768 225E9CDA-0384-4C92-92DD-E74C1153EC68\r\n',
  62. 'a=ssrc:4005 msid:7C0035E5-2DA1-4AEA-804A-9E75BF9B3768 225E9CDA-0384-4C92-92DD-E74C1153EC68\r\n',
  63. 'a=ssrc:4004 cname:juejgy8a01\r\n',
  64. 'a=ssrc:4005 cname:juejgy8a01\r\n',
  65. 'a=ssrc-group:FID 4004 4005\r\n',
  66. 'a=rtcp-mux\r\n'
  67. ].join('');
  68. /* eslint-enable max-len*/
  69. it('correctly groups ssrcs lines that are not in order', () => {
  70. const sdp = new SDP(testSdp);
  71. const accept = $iq({
  72. to: 'peerjid',
  73. type: 'set'
  74. })
  75. .c('jingle', {
  76. xmlns: 'urn:xmpp:jingle:1',
  77. action: 'session-accept',
  78. initiator: false,
  79. responder: true,
  80. sid: 'temp-sid'
  81. });
  82. sdp.toJingle(accept, false);
  83. const { nodeTree } = accept;
  84. const descriptions
  85. = Array.from(nodeTree.getElementsByTagName('description'));
  86. const videoDescriptions = descriptions.filter(description =>
  87. description.getAttribute('media') === 'video');
  88. const count = videoDescriptions.reduce((iterator, description) => {
  89. const childNodes = Array.from(description.childNodes);
  90. const childNodesSources = childNodes.filter(child =>
  91. child.nodeName === 'source');
  92. return iterator + childNodesSources.length;
  93. }, 0);
  94. expect(count).toBe(2);
  95. });
  96. });
  97. describe('fromJingle', () => {
  98. /* eslint-disable max-len*/
  99. const stanza = `<iq>
  100. <jingle action='session-initiate' initiator='focus' sid='123' xmlns='urn:xmpp:jingle:1'>
  101. <content creator='initiator' name='audio' senders='both'>
  102. <description media='audio' maxptime='60' xmlns='urn:xmpp:jingle:apps:rtp:1'>
  103. <payload-type channels='2' clockrate='48000' name='opus' id='111'>
  104. <parameter name='minptime' value='10'/>
  105. <parameter name='useinbandfec' value='1'/>
  106. <rtcp-fb type='transport-cc' xmlns='urn:xmpp:jingle:apps:rtp:rtcp-fb:0'/>
  107. </payload-type>
  108. <payload-type clockrate='16000' name='ISAC' id='103'/>
  109. <payload-type clockrate='32000' name='ISAC' id='104'/>
  110. <payload-type clockrate='8000' name='telephone-event' id='126'>
  111. <parameter name="" value="0-15"/>
  112. </payload-type>
  113. <rtp-hdrext uri='urn:ietf:params:rtp-hdrext:ssrc-audio-level' id='1' xmlns='urn:xmpp:jingle:apps:rtp:rtp-hdrext:0'/>
  114. <rtp-hdrext uri='http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01' id='5' xmlns='urn:xmpp:jingle:apps:rtp:rtp-hdrext:0'/>
  115. <rtcp-mux/>
  116. <source ssrc='4039389863' xmlns='urn:xmpp:jingle:apps:rtp:ssma:0'>
  117. <parameter name='cname' value='mixed'/>
  118. <parameter name='label' value='mixedlabelaudio0'/>
  119. <parameter name='msid' value='mixedmslabel mixedlabelaudio0'/>
  120. <parameter name='mslabel' value='mixedmslabel'/>
  121. </source>
  122. </description>
  123. <transport ufrag='someufrag' pwd='somepwd' xmlns='urn:xmpp:jingle:transports:ice-udp:1'>
  124. <fingerprint hash='sha-256' required='false' setup='actpass' xmlns='urn:xmpp:jingle:apps:dtls:0'>09:B1:51:0F:85:4C:80:19:A1:AF:81:73:47:EE:ED:3D:00:3A:84:C7:76:C1:4E:34:BE:56:F6:42:AD:15:D5:D7</fingerprint>
  125. <candidate foundation='1' id='3cbe5aea5bde0c1401a60bbc2' network='0' protocol='udp' generation='0' port='10000' priority='2130706431' type='host' ip='10.0.0.1' component='1'/>
  126. <candidate rel-addr='10.0.0.1' network='0' foundation='2' id='dfcfd075bde0c140ffffffff927646ba' port='10000' protocol='udp' generation='0' rel-port='10000' priority='1694498815' type='srflx' ip='10.0.0.2' component='1'/>
  127. </transport>
  128. </content>
  129. <content creator='initiator' name='video' senders='both'>
  130. <description media='video' xmlns='urn:xmpp:jingle:apps:rtp:1'>
  131. <payload-type clockrate='90000' name='VP8' id='100'>
  132. <rtcp-fb subtype='fir' type='ccm' xmlns='urn:xmpp:jingle:apps:rtp:rtcp-fb:0'/>
  133. <rtcp-fb type='nack' xmlns='urn:xmpp:jingle:apps:rtp:rtcp-fb:0'/>
  134. <rtcp-fb subtype='pli' type='nack' xmlns='urn:xmpp:jingle:apps:rtp:rtcp-fb:0'/>
  135. <rtcp-fb type='goog-remb' xmlns='urn:xmpp:jingle:apps:rtp:rtcp-fb:0'/>
  136. <rtcp-fb type='transport-cc' xmlns='urn:xmpp:jingle:apps:rtp:rtcp-fb:0'/>
  137. <parameter name='x-google-start-bitrate' value='800'/>
  138. </payload-type>
  139. <payload-type clockrate='90000' name='rtx' id='96'>
  140. <rtcp-fb subtype='fir' type='ccm' xmlns='urn:xmpp:jingle:apps:rtp:rtcp-fb:0'/>
  141. <rtcp-fb type='nack' xmlns='urn:xmpp:jingle:apps:rtp:rtcp-fb:0'/>
  142. <rtcp-fb subtype='pli' type='nack' xmlns='urn:xmpp:jingle:apps:rtp:rtcp-fb:0'/>
  143. <parameter name='apt' value='100'/>
  144. </payload-type>
  145. <rtp-hdrext uri='http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time' id='3' xmlns='urn:xmpp:jingle:apps:rtp:rtp-hdrext:0'/>
  146. <rtp-hdrext uri='http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01' id='5' xmlns='urn:xmpp:jingle:apps:rtp:rtp-hdrext:0'/>
  147. <rtcp-mux/>
  148. <source ssrc='3758540092' xmlns='urn:xmpp:jingle:apps:rtp:ssma:0'>
  149. <parameter name='cname' value='mixed'/>
  150. <parameter name='label' value='mixedlabelvideo0'/>
  151. <parameter name='msid' value='mixedmslabel mixedlabelvideo0'/>
  152. <parameter name='mslabel' value='mixedmslabel'/>
  153. </source>
  154. </description>
  155. <transport ufrag='someufrag' pwd='somepwd' xmlns='urn:xmpp:jingle:transports:ice-udp:1'>
  156. <fingerprint hash='sha-256' required='false' setup='actpass' xmlns='urn:xmpp:jingle:apps:dtls:0'>09:B1:51:0F:85:4C:80:19:A1:AF:81:73:47:EE:ED:3D:00:3A:84:C7:76:C1:4E:34:BE:56:F6:42:AD:15:D5:D7</fingerprint>
  157. <candidate foundation='1' id='3cbe5aea5bde0c1401a60bbc2' network='0' protocol='udp' generation='0' port='10000' priority='2130706431' type='host' ip='10.0.0.1' component='1'/>
  158. <candidate rel-addr='10.0.0.1' network='0' foundation='2' id='dfcfd075bde0c140ffffffff927646ba' port='10000' protocol='udp' generation='0' rel-port='10000' priority='1694498815' type='srflx' ip='10.0.0.2' component='1'/>
  159. </transport>
  160. </content>
  161. <group semantics='BUNDLE' xmlns='urn:xmpp:jingle:apps:grouping:0'>
  162. <content name='audio'/>
  163. <content name='video'/>
  164. </group>
  165. </jingle></iq>`;
  166. const expectedSDP = `v=0
  167. o=- 123 2 IN IP4 0.0.0.0
  168. s=-
  169. t=0 0
  170. a=group:BUNDLE audio video
  171. m=audio 1 RTP/SAVPF 111 103 104 126
  172. c=IN IP4 0.0.0.0
  173. a=rtcp:1 IN IP4 0.0.0.0
  174. a=ice-ufrag:someufrag
  175. a=ice-pwd:somepwd
  176. a=fingerprint:sha-256 09:B1:51:0F:85:4C:80:19:A1:AF:81:73:47:EE:ED:3D:00:3A:84:C7:76:C1:4E:34:BE:56:F6:42:AD:15:D5:D7
  177. a=setup:actpass
  178. a=candidate:1 1 udp 2130706431 10.0.0.1 10000 typ host generation 0
  179. a=candidate:2 1 udp 1694498815 10.0.0.2 10000 typ srflx raddr 10.0.0.1 rport 10000 generation 0
  180. a=sendrecv
  181. a=mid:audio
  182. a=rtcp-mux
  183. a=rtpmap:111 opus/48000/2
  184. a=fmtp:111 minptime=10; useinbandfec=1
  185. a=rtcp-fb:111 transport-cc
  186. a=rtpmap:103 ISAC/16000
  187. a=rtpmap:104 ISAC/32000
  188. a=rtpmap:126 telephone-event/8000
  189. a=fmtp:126 0-15
  190. a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
  191. a=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
  192. a=ssrc:4039389863 cname:mixed
  193. a=ssrc:4039389863 label:mixedlabelaudio0
  194. a=ssrc:4039389863 msid:mixedmslabel mixedlabelaudio0
  195. a=ssrc:4039389863 mslabel:mixedmslabel
  196. m=video 1 RTP/SAVPF 100 96
  197. c=IN IP4 0.0.0.0
  198. a=rtcp:1 IN IP4 0.0.0.0
  199. a=ice-ufrag:someufrag
  200. a=ice-pwd:somepwd
  201. a=fingerprint:sha-256 09:B1:51:0F:85:4C:80:19:A1:AF:81:73:47:EE:ED:3D:00:3A:84:C7:76:C1:4E:34:BE:56:F6:42:AD:15:D5:D7
  202. a=setup:actpass
  203. a=candidate:1 1 udp 2130706431 10.0.0.1 10000 typ host generation 0
  204. a=candidate:2 1 udp 1694498815 10.0.0.2 10000 typ srflx raddr 10.0.0.1 rport 10000 generation 0
  205. a=sendrecv
  206. a=mid:video
  207. a=rtcp-mux
  208. a=rtpmap:100 VP8/90000
  209. a=fmtp:100 x-google-start-bitrate=800
  210. a=rtcp-fb:100 ccm fir
  211. a=rtcp-fb:100 nack
  212. a=rtcp-fb:100 nack pli
  213. a=rtcp-fb:100 goog-remb
  214. a=rtcp-fb:100 transport-cc
  215. a=rtpmap:96 rtx/90000
  216. a=fmtp:96 apt=100
  217. a=rtcp-fb:96 ccm fir
  218. a=rtcp-fb:96 nack
  219. a=rtcp-fb:96 nack pli
  220. a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
  221. a=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
  222. a=ssrc:3758540092 cname:mixed
  223. a=ssrc:3758540092 label:mixedlabelvideo0
  224. a=ssrc:3758540092 msid:mixedmslabel mixedlabelvideo0
  225. a=ssrc:3758540092 mslabel:mixedmslabel
  226. `.split('\n').join('\r\n');
  227. /* eslint-enable max-len*/
  228. it('gets converted to SDP', () => {
  229. const offer = createStanzaElement(stanza);
  230. const sdp = new SDP('');
  231. sdp.fromJingle($(offer).find('>jingle'));
  232. const rawSDP = sdp.raw.replace(/o=- \d+/, 'o=- 123'); // replace generated o= timestamp.
  233. expect(rawSDP).toEqual(expectedSDP);
  234. });
  235. });
  236. });