Procházet zdrojové kódy

fix(sdp): group ssrcs when converting to jingle (#609)

Ssrcs not grouped together in the jingle element
are not recognized by the bridge. When parsing an
sdp with ssrcs that are not listed consecutively
it is important to still group them together
in the jingle element.
dev1
virtuacoplenny před 8 roky
rodič
revize
9f699bfeb5
3 změnil soubory, kde provedl 117 přidání a 67 odebrání
  1. 14
    63
      modules/xmpp/SDP.js
  2. 95
    0
      modules/xmpp/SDP.spec.js
  3. 8
    4
      modules/xmpp/SDPUtil.js

+ 14
- 63
modules/xmpp/SDP.js Zobrazit soubor

@@ -1,4 +1,4 @@
1
-/* global $, APP */
1
+/* global $ */
2 2
 
3 3
 import SDPUtil from './SDPUtil';
4 4
 
@@ -266,26 +266,18 @@ SDP.prototype.toJingle = function(elem, thecreator) {
266 266
             }
267 267
 
268 268
             if (ssrc) {
269
-                // new style mapping
270
-                elem.c('source', { ssrc,
271
-                    xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
272
-
273
-                // FIXME: group by ssrc and support multiple different ssrcs
274
-                const ssrclines = SDPUtil.findLines(this.media[i], 'a=ssrc:');
275
-
276
-                if (ssrclines.length > 0) {
277
-                    // eslint-disable-next-line no-loop-func
278
-                    ssrclines.forEach(line => {
279
-                        const idx = line.indexOf(' ');
280
-                        const linessrc = line.substr(0, idx).substr(7);
281
-
282
-                        if (linessrc !== ssrc) {
283
-                            elem.up();
284
-                            ssrc = linessrc;
285
-                            elem.c('source', { ssrc,
286
-                                xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
287
-                        }
288
-                        const kv = line.substr(idx + 1);
269
+                const ssrcMap = SDPUtil.parseSSRC(this.media[i]);
270
+
271
+                for (const [ availableSsrc, ssrcParameters ] of ssrcMap) {
272
+                    elem.c('source', {
273
+                        ssrc: availableSsrc,
274
+                        xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0'
275
+                    });
276
+
277
+                    ssrcParameters.forEach(ssrcSdpLine => {
278
+                        // get everything after first space
279
+                        const idx = ssrcSdpLine.indexOf(' ');
280
+                        const kv = ssrcSdpLine.substr(idx + 1);
289 281
 
290 282
                         elem.c('parameter');
291 283
                         if (kv.indexOf(':') === -1) {
@@ -302,50 +294,9 @@ SDP.prototype.toJingle = function(elem, thecreator) {
302 294
                         }
303 295
                         elem.up();
304 296
                     });
305
-                } else {
306
-                    elem.up();
307
-                    elem.c('source', { ssrc,
308
-                        xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
309
-                    elem.c('parameter');
310
-                    elem.attrs({
311
-                        name: 'cname',
312
-
313
-                        // eslint-disable-next-line newline-per-chained-call
314
-                        value: Math.random().toString(36).substring(7)
315
-                    });
316
-                    elem.up();
317
-
318
-                    // FIXME what case does this code handle ? remove ???
319
-                    let msid = null;
320
-
321
-                    // FIXME what is this ? global APP.RTC in SDP ?
322
-                    const localTrack = APP.RTC.getLocalTracks(mline.media);
323
-
324
-                    // eslint-disable-next-line max-depth
325
-                    if (localTrack) {
326
-                        // FIXME before this changes the track id was accessed,
327
-                        // but msid stands for the stream id, makes no sense ?
328
-                        msid = localTrack.getTrackId();
329
-                    }
330 297
 
331
-                    // eslint-disable-next-line max-depth
332
-                    if (msid !== null) {
333
-                        msid = SDPUtil.filterSpecialChars(msid);
334
-                        elem.c('parameter');
335
-                        elem.attrs({ name: 'msid',
336
-                            value: msid });
337
-                        elem.up();
338
-                        elem.c('parameter');
339
-                        elem.attrs({ name: 'mslabel',
340
-                            value: msid });
341
-                        elem.up();
342
-                        elem.c('parameter');
343
-                        elem.attrs({ name: 'label',
344
-                            value: msid });
345
-                        elem.up();
346
-                    }
298
+                    elem.up();
347 299
                 }
348
-                elem.up();
349 300
 
350 301
                 // XEP-0339 handle ssrc-group attributes
351 302
                 const ssrcGroupLines

+ 95
- 0
modules/xmpp/SDP.spec.js Zobrazit soubor

@@ -0,0 +1,95 @@
1
+import { $iq } from 'strophe.js';
2
+import SDP from './SDP';
3
+
4
+describe('SDP', () => {
5
+    describe('toJingle', () => {
6
+        /* eslint-disable max-len*/
7
+        const testSdp = [
8
+            'v=0\r\n',
9
+            'o=thisisadapterortc 2719486166053431 0 IN IP4 127.0.0.1\r\n',
10
+            's=-\r\n',
11
+            't=0 0\r\n',
12
+            'a=group:BUNDLE audio video\r\n',
13
+            'm=audio 9 UDP/TLS/RTP/SAVPF 111 126\r\n',
14
+            'c=IN IP4 0.0.0.0\r\n',
15
+            'a=rtpmap:111 opus/48000/2\r\n',
16
+            'a=rtpmap:126 telephone-event/8000\r\n',
17
+            'a=fmtp:111 minptime=10;useinbandfec=1\r\n',
18
+            'a=rtcp:9 IN IP4 0.0.0.0\r\n',
19
+            'a=setup:active\r\n',
20
+            'a=mid:audio\r\n',
21
+            'a=msid:26D16D51-503A-420B-8274-3DD1174E498F 8205D1FC-50B4-407C-87D5-9C45F1B779F0\r\n',
22
+            'a=sendrecv\r\n',
23
+            'a=ice-ufrag:tOQd\r\n',
24
+            'a=ice-pwd:3sAozs7hw6+2O6DBp2pt9fvY\r\n',
25
+            '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',
26
+            'a=ssrc:2002 msid:26D16D51-503A-420B-8274-3DD1174E498F 8205D1FC-50B4-407C-87D5-9C45F1B779F0\r\n',
27
+            'a=ssrc:2002 cname:juejgy8a01\r\n',
28
+            'a=rtcp-mux\r\n',
29
+            'm=video 9 UDP/TLS/RTP/SAVPF 107 100 99 96\r\n',
30
+            'c=IN IP4 0.0.0.0\r\n',
31
+            'a=rtpmap:107 h264/90000\r\n',
32
+            'a=rtpmap:100 VP8/90000\r\n',
33
+            'a=rtpmap:99 rtx/90000\r\n',
34
+            'a=rtpmap:96 rtx/90000\r\n',
35
+            'a=fmtp:107 x-google-start-bitrate=800\r\n',
36
+            'a=fmtp:100 x-google-start-bitrate=800\r\n',
37
+            'a=fmtp:99 apt=107\r\n',
38
+            'a=fmtp:96 apt=100\r\n',
39
+            'a=rtcp:9 IN IP4 0.0.0.0\r\n',
40
+            'a=rtcp-fb:107 nack\r\n',
41
+            'a=rtcp-fb:107 nack pli\r\n',
42
+            'a=rtcp-fb:107 goog-remb\r\n',
43
+            'a=rtcp-fb:100 nack\r\n',
44
+            'a=rtcp-fb:100 nack pli\r\n',
45
+            'a=rtcp-fb:100 goog-remb\r\n',
46
+            'a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\n',
47
+            'a=setup:active\r\n',
48
+            'a=mid:video\r\n',
49
+            'a=msid:7C0035E5-2DA1-4AEA-804A-9E75BF9B3768 225E9CDA-0384-4C92-92DD-E74C1153EC68\r\n',
50
+            'a=sendrecv\r\n',
51
+            'a=ice-ufrag:tOQd\r\n',
52
+            'a=ice-pwd:3sAozs7hw6+2O6DBp2pt9fvY\r\n',
53
+            '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',
54
+            'a=ssrc:4004 msid:7C0035E5-2DA1-4AEA-804A-9E75BF9B3768 225E9CDA-0384-4C92-92DD-E74C1153EC68\r\n',
55
+            'a=ssrc:4005 msid:7C0035E5-2DA1-4AEA-804A-9E75BF9B3768 225E9CDA-0384-4C92-92DD-E74C1153EC68\r\n',
56
+            'a=ssrc:4004 cname:juejgy8a01\r\n',
57
+            'a=ssrc:4005 cname:juejgy8a01\r\n',
58
+            'a=ssrc-group:FID 4004 4005\r\n',
59
+            'a=rtcp-mux\r\n'
60
+        ].join('');
61
+        /* eslint-enable max-len*/
62
+
63
+        it('correctly groups ssrcs lines that are not in order', () => {
64
+            const sdp = new SDP(testSdp);
65
+            const accept = $iq({
66
+                to: 'peerjid',
67
+                type: 'set'
68
+            })
69
+            .c('jingle', {
70
+                xmlns: 'urn:xmpp:jingle:1',
71
+                action: 'session-accept',
72
+                initiator: false,
73
+                responder: true,
74
+                sid: 'temp-sid'
75
+            });
76
+
77
+            sdp.toJingle(accept, false);
78
+
79
+            const { nodeTree } = accept;
80
+            const descriptions
81
+                = Array.from(nodeTree.getElementsByTagName('description'));
82
+            const videoDescriptions = descriptions.filter(description =>
83
+                description.getAttribute('media') === 'video');
84
+            const count = videoDescriptions.reduce((iterator, description) => {
85
+                const childNodes = Array.from(description.childNodes);
86
+                const childNodesSources = childNodes.filter(child =>
87
+                    child.nodeName === 'source');
88
+
89
+                return iterator + childNodesSources.length;
90
+            }, 0);
91
+
92
+            expect(count).toBe(2);
93
+        });
94
+    });
95
+});

+ 8
- 4
modules/xmpp/SDPUtil.js Zobrazit soubor

@@ -241,15 +241,19 @@ const SDPUtil = {
241 241
         // proprietary mapping of a=ssrc lines
242 242
         // TODO: see "Jingle RTP Source Description" by Juberti and P. Thatcher
243 243
         // on google docs and parse according to that
244
-        const data = {};
244
+        const data = new Map();
245 245
         const lines = desc.split('\r\n');
246 246
 
247 247
         for (let i = 0; i < lines.length; i++) {
248 248
             if (lines[i].substring(0, 7) === 'a=ssrc:') {
249
-                const idx = lines[i].indexOf(' ');
249
+                // FIXME: Use regex to smartly find the ssrc.
250
+                const ssrc = lines[i].split('a=ssrc:')[1].split(' ')[0];
251
+
252
+                if (!data.get(ssrc)) {
253
+                    data.set(ssrc, []);
254
+                }
250 255
 
251
-                data[lines[i].substr(idx + 1).split(':', 2)[0]]
252
-                    = lines[i].substr(idx + 1).split(':', 2)[1];
256
+                data.get(ssrc).push(lines[i]);
253 257
             }
254 258
         }
255 259
 

Načítá se…
Zrušit
Uložit