|
@@ -44,8 +44,21 @@ function ColibriFocus(connection, bridgejid) {
|
44
|
44
|
this.peers = [];
|
45
|
45
|
this.confid = null;
|
46
|
46
|
|
|
47
|
+ /**
|
|
48
|
+ * Default channel expire value in seconds.
|
|
49
|
+ * @type {number}
|
|
50
|
+ */
|
|
51
|
+ this.channelExpire = 60;
|
|
52
|
+
|
47
|
53
|
// media types of the conference
|
48
|
|
- this.media = ['audio', 'video'];
|
|
54
|
+ if (config.openSctp)
|
|
55
|
+ {
|
|
56
|
+ this.media = ['audio', 'video', 'data'];
|
|
57
|
+ }
|
|
58
|
+ else
|
|
59
|
+ {
|
|
60
|
+ this.media = ['audio', 'video'];
|
|
61
|
+ }
|
49
|
62
|
|
50
|
63
|
this.connection.jingle.sessions[this.sid] = this;
|
51
|
64
|
this.mychannel = [];
|
|
@@ -151,17 +164,29 @@ ColibriFocus.prototype._makeConference = function () {
|
151
|
164
|
elem.c('conference', {xmlns: 'http://jitsi.org/protocol/colibri'});
|
152
|
165
|
|
153
|
166
|
this.media.forEach(function (name) {
|
|
167
|
+ var isData = name === 'data';
|
|
168
|
+ var channel = isData ? 'sctpconnection' : 'channel';
|
|
169
|
+
|
154
|
170
|
elem.c('content', {name: name});
|
155
|
|
- elem.c('channel', {
|
|
171
|
+
|
|
172
|
+ elem.c(channel, {
|
156
|
173
|
initiator: 'true',
|
157
|
174
|
expire: '15',
|
158
|
|
- endpoint: 'fix_me_focus_endpoint'}).up();
|
|
175
|
+ endpoint: 'fix_me_focus_endpoint'
|
|
176
|
+ });
|
|
177
|
+ if (isData)
|
|
178
|
+ elem.attrs({port: 5000});
|
|
179
|
+ elem.up();// end of channel
|
|
180
|
+
|
159
|
181
|
for (var j = 0; j < self.peers.length; j++) {
|
160
|
|
- elem.c('channel', {
|
|
182
|
+ elem.c(channel, {
|
161
|
183
|
initiator: 'true',
|
162
|
184
|
expire: '15',
|
163
|
185
|
endpoint: self.peers[j].substr(1 + self.peers[j].lastIndexOf('/'))
|
164
|
|
- }).up();
|
|
186
|
+ });
|
|
187
|
+ if (isData)
|
|
188
|
+ elem.attrs({port: 5000});
|
|
189
|
+ elem.up(); // end of channel
|
165
|
190
|
}
|
166
|
191
|
elem.up(); // end of content
|
167
|
192
|
});
|
|
@@ -209,8 +234,13 @@ ColibriFocus.prototype.createdConference = function (result) {
|
209
|
234
|
this.confid = $(result).find('>conference').attr('id');
|
210
|
235
|
var remotecontents = $(result).find('>conference>content').get();
|
211
|
236
|
var numparticipants = 0;
|
212
|
|
- for (var i = 0; i < remotecontents.length; i++) {
|
213
|
|
- tmp = $(remotecontents[i]).find('>channel').get();
|
|
237
|
+ for (var i = 0; i < remotecontents.length; i++)
|
|
238
|
+ {
|
|
239
|
+ var contentName = $(remotecontents[i]).attr('name');
|
|
240
|
+ var channelName
|
|
241
|
+ = contentName !== 'data' ? '>channel' : '>sctpconnection';
|
|
242
|
+
|
|
243
|
+ tmp = $(remotecontents[i]).find(channelName).get();
|
214
|
244
|
this.mychannel.push($(tmp.shift()));
|
215
|
245
|
numparticipants = tmp.length;
|
216
|
246
|
for (j = 0; j < tmp.length; j++) {
|
|
@@ -223,7 +253,55 @@ ColibriFocus.prototype.createdConference = function (result) {
|
223
|
253
|
|
224
|
254
|
console.log('remote channels', this.channels);
|
225
|
255
|
|
226
|
|
- var bridgeSDP = new SDP('v=0\r\no=- 5151055458874951233 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\nm=audio 1 RTP/SAVPF 111 103 104 0 8 106 105 13 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:1 IN IP4 0.0.0.0\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=sendrecv\r\na=rtpmap:111 opus/48000/2\r\na=fmtp:111 minptime=10\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:126 telephone-event/8000\r\na=maxptime:60\r\nm=video 1 RTP/SAVPF 100 116 117\r\nc=IN IP4 0.0.0.0\r\na=rtcp:1 IN IP4 0.0.0.0\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=sendrecv\r\na=rtpmap:100 VP8/90000\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 goog-remb\r\na=rtpmap:116 red/90000\r\na=rtpmap:117 ulpfec/90000\r\n');
|
|
256
|
+ // Notify that the focus has created the conference on the bridge
|
|
257
|
+ $(document).trigger('conferenceCreated.jingle', [self]);
|
|
258
|
+
|
|
259
|
+ var bridgeSDP = new SDP(
|
|
260
|
+ 'v=0\r\n' +
|
|
261
|
+ 'o=- 5151055458874951233 2 IN IP4 127.0.0.1\r\n' +
|
|
262
|
+ 's=-\r\n' +
|
|
263
|
+ 't=0 0\r\n' +
|
|
264
|
+ /* Audio */
|
|
265
|
+ 'm=audio 1 RTP/SAVPF 111 103 104 0 8 106 105 13 126\r\n' +
|
|
266
|
+ 'c=IN IP4 0.0.0.0\r\n' +
|
|
267
|
+ 'a=rtcp:1 IN IP4 0.0.0.0\r\n' +
|
|
268
|
+ 'a=mid:audio\r\n' +
|
|
269
|
+ 'a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\n' +
|
|
270
|
+ 'a=sendrecv\r\n' +
|
|
271
|
+ 'a=rtpmap:111 opus/48000/2\r\n' +
|
|
272
|
+ 'a=fmtp:111 minptime=10\r\n' +
|
|
273
|
+ 'a=rtpmap:103 ISAC/16000\r\n' +
|
|
274
|
+ 'a=rtpmap:104 ISAC/32000\r\n' +
|
|
275
|
+ 'a=rtpmap:0 PCMU/8000\r\n' +
|
|
276
|
+ 'a=rtpmap:8 PCMA/8000\r\n' +
|
|
277
|
+ 'a=rtpmap:106 CN/32000\r\n' +
|
|
278
|
+ 'a=rtpmap:105 CN/16000\r\n' +
|
|
279
|
+ 'a=rtpmap:13 CN/8000\r\n' +
|
|
280
|
+ 'a=rtpmap:126 telephone-event/8000\r\n' +
|
|
281
|
+ 'a=maxptime:60\r\n' +
|
|
282
|
+ /* Video */
|
|
283
|
+ 'm=video 1 RTP/SAVPF 100 116 117\r\n' +
|
|
284
|
+ 'c=IN IP4 0.0.0.0\r\n' +
|
|
285
|
+ 'a=rtcp:1 IN IP4 0.0.0.0\r\n' +
|
|
286
|
+ 'a=mid:video\r\n' +
|
|
287
|
+ 'a=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\n' +
|
|
288
|
+ 'a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\n' +
|
|
289
|
+ 'a=sendrecv\r\n' +
|
|
290
|
+ 'a=rtpmap:100 VP8/90000\r\n' +
|
|
291
|
+ 'a=rtcp-fb:100 ccm fir\r\n' +
|
|
292
|
+ 'a=rtcp-fb:100 nack\r\n' +
|
|
293
|
+ 'a=rtcp-fb:100 goog-remb\r\n' +
|
|
294
|
+ 'a=rtpmap:116 red/90000\r\n' +
|
|
295
|
+ 'a=rtpmap:117 ulpfec/90000\r\n' +
|
|
296
|
+ /* Data SCTP */
|
|
297
|
+ (config.openSctp ?
|
|
298
|
+ 'm=application 1 DTLS/SCTP 5000\r\n' +
|
|
299
|
+ 'c=IN IP4 0.0.0.0\r\n' +
|
|
300
|
+ 'a=sctpmap:5000 webrtc-datachannel\r\n' +
|
|
301
|
+ 'a=mid:data\r\n'
|
|
302
|
+ : '')
|
|
303
|
+ );
|
|
304
|
+
|
227
|
305
|
bridgeSDP.media.length = this.mychannel.length;
|
228
|
306
|
var channel;
|
229
|
307
|
/*
|
|
@@ -262,12 +340,17 @@ ColibriFocus.prototype.createdConference = function (result) {
|
262
|
340
|
// get the mixed ssrc
|
263
|
341
|
tmp = $(this.mychannel[channel]).find('>source[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]');
|
264
|
342
|
// FIXME: check rtp-level-relay-type
|
265
|
|
- if (tmp.length) {
|
|
343
|
+
|
|
344
|
+ var isData = bridgeSDP.media[channel].indexOf('application') !== -1;
|
|
345
|
+ if (!isData && tmp.length)
|
|
346
|
+ {
|
266
|
347
|
bridgeSDP.media[channel] += 'a=ssrc:' + tmp.attr('ssrc') + ' ' + 'cname:mixed' + '\r\n';
|
267
|
348
|
bridgeSDP.media[channel] += 'a=ssrc:' + tmp.attr('ssrc') + ' ' + 'label:mixedlabela0' + '\r\n';
|
268
|
349
|
bridgeSDP.media[channel] += 'a=ssrc:' + tmp.attr('ssrc') + ' ' + 'msid:mixedmslabel mixedlabela0' + '\r\n';
|
269
|
350
|
bridgeSDP.media[channel] += 'a=ssrc:' + tmp.attr('ssrc') + ' ' + 'mslabel:mixedmslabel' + '\r\n';
|
270
|
|
- } else {
|
|
351
|
+ }
|
|
352
|
+ else if (!isData)
|
|
353
|
+ {
|
271
|
354
|
// make chrome happy... '3735928559' == 0xDEADBEEF
|
272
|
355
|
// FIXME: this currently appears as two streams, should be one
|
273
|
356
|
bridgeSDP.media[channel] += 'a=ssrc:' + '3735928559' + ' ' + 'cname:mixed' + '\r\n';
|
|
@@ -308,21 +391,41 @@ ColibriFocus.prototype.createdConference = function (result) {
|
308
|
391
|
elem.c('conference', {xmlns: 'http://jitsi.org/protocol/colibri', id: self.confid});
|
309
|
392
|
var localSDP = new SDP(self.peerconnection.localDescription.sdp);
|
310
|
393
|
localSDP.media.forEach(function (media, channel) {
|
311
|
|
- var name = SDPUtil.parse_mline(media.split('\r\n')[0]).media;
|
|
394
|
+ var name = SDPUtil.parse_mid(SDPUtil.find_line(media, 'a=mid:'));
|
312
|
395
|
elem.c('content', {name: name});
|
313
|
|
- elem.c('channel', {
|
314
|
|
- initiator: 'true',
|
315
|
|
- expire: '15',
|
316
|
|
- id: self.mychannel[channel].attr('id'),
|
317
|
|
- endpoint: 'fix_me_focus_endpoint'
|
318
|
|
- });
|
319
|
|
-
|
320
|
|
- // FIXME: should reuse code from .toJingle
|
321
|
396
|
var mline = SDPUtil.parse_mline(media.split('\r\n')[0]);
|
322
|
|
- for (var j = 0; j < mline.fmt.length; j++) {
|
323
|
|
- var rtpmap = SDPUtil.find_line(media, 'a=rtpmap:' + mline.fmt[j]);
|
324
|
|
- elem.c('payload-type', SDPUtil.parse_rtpmap(rtpmap));
|
325
|
|
- elem.up();
|
|
397
|
+ if (name !== 'data')
|
|
398
|
+ {
|
|
399
|
+ elem.c('channel', {
|
|
400
|
+ initiator: 'true',
|
|
401
|
+ expire: self.channelExpire,
|
|
402
|
+ id: self.mychannel[channel].attr('id'),
|
|
403
|
+ endpoint: 'fix_me_focus_endpoint'
|
|
404
|
+ });
|
|
405
|
+
|
|
406
|
+ // FIXME: should reuse code from .toJingle
|
|
407
|
+ for (var j = 0; j < mline.fmt.length; j++)
|
|
408
|
+ {
|
|
409
|
+ var rtpmap = SDPUtil.find_line(media, 'a=rtpmap:' + mline.fmt[j]);
|
|
410
|
+ if (rtpmap)
|
|
411
|
+ {
|
|
412
|
+ elem.c('payload-type', SDPUtil.parse_rtpmap(rtpmap));
|
|
413
|
+ elem.up();
|
|
414
|
+ }
|
|
415
|
+ }
|
|
416
|
+ }
|
|
417
|
+ else
|
|
418
|
+ {
|
|
419
|
+ var sctpmap = SDPUtil.find_line(media, 'a=sctpmap:' + mline.fmt[0]);
|
|
420
|
+ var sctpPort = SDPUtil.parse_sctpmap(sctpmap);
|
|
421
|
+ elem.c("sctpconnection",
|
|
422
|
+ {
|
|
423
|
+ initiator: 'true',
|
|
424
|
+ expire: self.channelExpire,
|
|
425
|
+ endpoint: 'fix_me_focus_endpoint',
|
|
426
|
+ port: sctpPort
|
|
427
|
+ }
|
|
428
|
+ );
|
326
|
429
|
}
|
327
|
430
|
|
328
|
431
|
localSDP.TransportToJingle(channel, elem);
|
|
@@ -336,7 +439,9 @@ ColibriFocus.prototype.createdConference = function (result) {
|
336
|
439
|
// ...
|
337
|
440
|
},
|
338
|
441
|
function (error) {
|
339
|
|
- console.warn(error);
|
|
442
|
+ console.error(
|
|
443
|
+ "ERROR setLocalDescription succeded",
|
|
444
|
+ error, elem);
|
340
|
445
|
}
|
341
|
446
|
);
|
342
|
447
|
|
|
@@ -417,7 +522,10 @@ ColibriFocus.prototype.initiate = function (peer, isInitiator) {
|
417
|
522
|
sdp.media[j] += 'a=ssrc:' + tmp.attr('ssrc') + ' ' + 'label:mixedlabela0' + '\r\n';
|
418
|
523
|
sdp.media[j] += 'a=ssrc:' + tmp.attr('ssrc') + ' ' + 'msid:mixedmslabel mixedlabela0' + '\r\n';
|
419
|
524
|
sdp.media[j] += 'a=ssrc:' + tmp.attr('ssrc') + ' ' + 'mslabel:mixedmslabel' + '\r\n';
|
420
|
|
- } else {
|
|
525
|
+ }
|
|
526
|
+ // No SSRCs for 'data', comes when j == 2
|
|
527
|
+ else if (j < 2)
|
|
528
|
+ {
|
421
|
529
|
// make chrome happy... '3735928559' == 0xDEADBEEF
|
422
|
530
|
sdp.media[j] += 'a=ssrc:' + '3735928559' + ' ' + 'cname:mixed' + '\r\n';
|
423
|
531
|
sdp.media[j] += 'a=ssrc:' + '3735928559' + ' ' + 'label:mixedlabelv0' + '\r\n';
|
|
@@ -486,9 +594,17 @@ ColibriFocus.prototype.initiate = function (peer, isInitiator) {
|
486
|
594
|
// pull in a new participant into the conference
|
487
|
595
|
ColibriFocus.prototype.addNewParticipant = function (peer) {
|
488
|
596
|
var self = this;
|
489
|
|
- if (this.confid === 0) {
|
|
597
|
+ if (this.confid === 0 || !this.peerconnection.localDescription)
|
|
598
|
+ {
|
490
|
599
|
// bad state
|
491
|
|
- console.log('confid does not exist yet, postponing', peer);
|
|
600
|
+ if (this.confid === 0)
|
|
601
|
+ {
|
|
602
|
+ console.error('confid does not exist yet, postponing', peer);
|
|
603
|
+ }
|
|
604
|
+ else
|
|
605
|
+ {
|
|
606
|
+ console.error('local description not ready yet, postponing', peer);
|
|
607
|
+ }
|
492
|
608
|
window.setTimeout(function () {
|
493
|
609
|
self.addNewParticipant(peer);
|
494
|
610
|
}, 250);
|
|
@@ -502,14 +618,26 @@ ColibriFocus.prototype.addNewParticipant = function (peer) {
|
502
|
618
|
elem.c('conference', {xmlns: 'http://jitsi.org/protocol/colibri', id: this.confid});
|
503
|
619
|
var localSDP = new SDP(this.peerconnection.localDescription.sdp);
|
504
|
620
|
localSDP.media.forEach(function (media, channel) {
|
505
|
|
- var name = SDPUtil.parse_mline(media.split('\r\n')[0]).media;
|
|
621
|
+ var name = SDPUtil.parse_mid(SDPUtil.find_line(media, 'a=mid:'));
|
506
|
622
|
elem.c('content', {name: name});
|
507
|
|
- elem.c('channel', {
|
|
623
|
+ if (name !== 'data')
|
|
624
|
+ {
|
|
625
|
+ elem.c('channel', {
|
508
|
626
|
initiator: 'true',
|
509
|
|
- expire:'15',
|
|
627
|
+ expire: self.channelExpire,
|
510
|
628
|
endpoint: peer.substr(1 + peer.lastIndexOf('/'))
|
511
|
|
- });
|
512
|
|
- elem.up(); // end of channel
|
|
629
|
+ });
|
|
630
|
+ }
|
|
631
|
+ else
|
|
632
|
+ {
|
|
633
|
+ elem.c('sctpconnection', {
|
|
634
|
+ endpoint: peer.substr(1 + peer.lastIndexOf('/')),
|
|
635
|
+ initiator: 'true',
|
|
636
|
+ expire: self.channelExpire,
|
|
637
|
+ port: 5000
|
|
638
|
+ });
|
|
639
|
+ }
|
|
640
|
+ elem.up(); // end of channel/sctpconnection
|
513
|
641
|
elem.up(); // end of content
|
514
|
642
|
});
|
515
|
643
|
|
|
@@ -517,7 +645,15 @@ ColibriFocus.prototype.addNewParticipant = function (peer) {
|
517
|
645
|
function (result) {
|
518
|
646
|
var contents = $(result).find('>conference>content').get();
|
519
|
647
|
for (var i = 0; i < contents.length; i++) {
|
520
|
|
- tmp = $(contents[i]).find('>channel').get();
|
|
648
|
+ var channelXml = $(contents[i]).find('>channel');
|
|
649
|
+ if (channelXml.length)
|
|
650
|
+ {
|
|
651
|
+ tmp = channelXml.get();
|
|
652
|
+ }
|
|
653
|
+ else
|
|
654
|
+ {
|
|
655
|
+ tmp = $(contents[i]).find('>sctpconnection').get();
|
|
656
|
+ }
|
521
|
657
|
self.channels[index][i] = tmp[0];
|
522
|
658
|
}
|
523
|
659
|
self.initiate(peer, true);
|
|
@@ -531,37 +667,52 @@ ColibriFocus.prototype.addNewParticipant = function (peer) {
|
531
|
667
|
// update the channel description (payload-types + dtls fp) for a participant
|
532
|
668
|
ColibriFocus.prototype.updateChannel = function (remoteSDP, participant) {
|
533
|
669
|
console.log('change allocation for', this.confid);
|
|
670
|
+ var self = this;
|
534
|
671
|
var change = $iq({to: this.bridgejid, type: 'set'});
|
535
|
672
|
change.c('conference', {xmlns: 'http://jitsi.org/protocol/colibri', id: this.confid});
|
536
|
|
- for (channel = 0; channel < this.channels[participant].length; channel++) {
|
537
|
|
- change.c('content', {name: channel === 0 ? 'audio' : 'video'});
|
538
|
|
- change.c('channel', {
|
539
|
|
- id: $(this.channels[participant][channel]).attr('id'),
|
540
|
|
- endpoint: $(this.channels[participant][channel]).attr('endpoint'),
|
541
|
|
- expire: '15'
|
542
|
|
- });
|
|
673
|
+ for (channel = 0; channel < this.channels[participant].length; channel++)
|
|
674
|
+ {
|
|
675
|
+ var name = SDPUtil.parse_mid(SDPUtil.find_line(remoteSDP.media[channel], 'a=mid:'));
|
|
676
|
+ change.c('content', {name: name});
|
|
677
|
+ if (name !== 'data')
|
|
678
|
+ {
|
|
679
|
+ change.c('channel', {
|
|
680
|
+ id: $(this.channels[participant][channel]).attr('id'),
|
|
681
|
+ endpoint: $(this.channels[participant][channel]).attr('endpoint'),
|
|
682
|
+ expire: self.channelExpire
|
|
683
|
+ });
|
543
|
684
|
|
544
|
|
- var rtpmap = SDPUtil.find_lines(remoteSDP.media[channel], 'a=rtpmap:');
|
545
|
|
- rtpmap.forEach(function (val) {
|
546
|
|
- // TODO: too much copy-paste
|
547
|
|
- var rtpmap = SDPUtil.parse_rtpmap(val);
|
548
|
|
- change.c('payload-type', rtpmap);
|
549
|
|
- //
|
550
|
|
- // put any 'a=fmtp:' + mline.fmt[j] lines into <param name=foo value=bar/>
|
551
|
|
- /*
|
552
|
|
- if (SDPUtil.find_line(remoteSDP.media[channel], 'a=fmtp:' + rtpmap.id)) {
|
553
|
|
- tmp = SDPUtil.parse_fmtp(SDPUtil.find_line(remoteSDP.media[channel], 'a=fmtp:' + rtpmap.id));
|
554
|
|
- for (var k = 0; k < tmp.length; k++) {
|
555
|
|
- change.c('parameter', tmp[k]).up();
|
|
685
|
+ var rtpmap = SDPUtil.find_lines(remoteSDP.media[channel], 'a=rtpmap:');
|
|
686
|
+ rtpmap.forEach(function (val) {
|
|
687
|
+ // TODO: too much copy-paste
|
|
688
|
+ var rtpmap = SDPUtil.parse_rtpmap(val);
|
|
689
|
+ change.c('payload-type', rtpmap);
|
|
690
|
+ //
|
|
691
|
+ // put any 'a=fmtp:' + mline.fmt[j] lines into <param name=foo value=bar/>
|
|
692
|
+ /*
|
|
693
|
+ if (SDPUtil.find_line(remoteSDP.media[channel], 'a=fmtp:' + rtpmap.id)) {
|
|
694
|
+ tmp = SDPUtil.parse_fmtp(SDPUtil.find_line(remoteSDP.media[channel], 'a=fmtp:' + rtpmap.id));
|
|
695
|
+ for (var k = 0; k < tmp.length; k++) {
|
|
696
|
+ change.c('parameter', tmp[k]).up();
|
|
697
|
+ }
|
556
|
698
|
}
|
557
|
|
- }
|
558
|
|
- */
|
559
|
|
- change.up();
|
560
|
|
- });
|
|
699
|
+ */
|
|
700
|
+ change.up();
|
|
701
|
+ });
|
|
702
|
+ }
|
|
703
|
+ else
|
|
704
|
+ {
|
|
705
|
+ var sctpmap = SDPUtil.find_line(remoteSDP.media[channel], 'a=sctpmap:');
|
|
706
|
+ change.c('sctpconnection', {
|
|
707
|
+ endpoint: $(this.channels[participant][channel]).attr('endpoint'),
|
|
708
|
+ expire: self.channelExpire,
|
|
709
|
+ port: SDPUtil.parse_sctpmap(sctpmap)
|
|
710
|
+ });
|
|
711
|
+ }
|
561
|
712
|
// now add transport
|
562
|
713
|
remoteSDP.TransportToJingle(channel, change);
|
563
|
714
|
|
564
|
|
- change.up(); // end of channel
|
|
715
|
+ change.up(); // end of channel/sctpconnection
|
565
|
716
|
change.up(); // end of content
|
566
|
717
|
}
|
567
|
718
|
this.connection.sendIQ(change,
|
|
@@ -675,8 +826,11 @@ ColibriFocus.prototype.setRemoteDescription = function (session, elem, desctype)
|
675
|
826
|
this.remotessrc[session.peerjid] = [];
|
676
|
827
|
for (channel = 0; channel < this.channels[participant].length; channel++) {
|
677
|
828
|
//if (channel == 0) continue; FIXME: does not work as intended
|
678
|
|
- if (SDPUtil.find_lines(remoteSDP.media[channel], 'a=ssrc:').length) {
|
679
|
|
- this.remotessrc[session.peerjid][channel] = SDPUtil.find_lines(remoteSDP.media[channel], 'a=ssrc:').join('\r\n') + '\r\n';
|
|
829
|
+ if (SDPUtil.find_lines(remoteSDP.media[channel], 'a=ssrc:').length)
|
|
830
|
+ {
|
|
831
|
+ this.remotessrc[session.peerjid][channel] =
|
|
832
|
+ SDPUtil.find_lines(remoteSDP.media[channel], 'a=ssrc:')
|
|
833
|
+ .join('\r\n') + '\r\n';
|
680
|
834
|
}
|
681
|
835
|
}
|
682
|
836
|
|
|
@@ -702,14 +856,27 @@ ColibriFocus.prototype.addIceCandidate = function (session, elem) {
|
702
|
856
|
change.c('conference', {xmlns: 'http://jitsi.org/protocol/colibri', id: this.confid});
|
703
|
857
|
$(elem).each(function () {
|
704
|
858
|
var name = $(this).attr('name');
|
|
859
|
+
|
705
|
860
|
var channel = name == 'audio' ? 0 : 1; // FIXME: search mlineindex in localdesc
|
|
861
|
+ if (name != 'audio' && name != 'video')
|
|
862
|
+ channel = 2; // name == 'data'
|
706
|
863
|
|
707
|
864
|
change.c('content', {name: name});
|
708
|
|
- change.c('channel', {
|
709
|
|
- id: $(self.channels[participant][channel]).attr('id'),
|
710
|
|
- endpoint: $(self.channels[participant][channel]).attr('endpoint'),
|
711
|
|
- expire: '15'
|
712
|
|
- });
|
|
865
|
+ if (name !== 'data')
|
|
866
|
+ {
|
|
867
|
+ change.c('channel', {
|
|
868
|
+ id: $(self.channels[participant][channel]).attr('id'),
|
|
869
|
+ endpoint: $(self.channels[participant][channel]).attr('endpoint'),
|
|
870
|
+ expire: self.channelExpire
|
|
871
|
+ });
|
|
872
|
+ }
|
|
873
|
+ else
|
|
874
|
+ {
|
|
875
|
+ change.c('sctpconnection', {
|
|
876
|
+ endpoint: $(self.channels[participant][channel]).attr('endpoint'),
|
|
877
|
+ expire: self.channelExpire
|
|
878
|
+ });
|
|
879
|
+ }
|
713
|
880
|
$(this).find('>transport').each(function () {
|
714
|
881
|
change.c('transport', {
|
715
|
882
|
ufrag: $(this).attr('ufrag'),
|
|
@@ -729,7 +896,7 @@ ColibriFocus.prototype.addIceCandidate = function (session, elem) {
|
729
|
896
|
});
|
730
|
897
|
change.up(); // end of transport
|
731
|
898
|
});
|
732
|
|
- change.up(); // end of channel
|
|
899
|
+ change.up(); // end of channel/sctpconnection
|
733
|
900
|
change.up(); // end of content
|
734
|
901
|
});
|
735
|
902
|
// FIXME: need to check if there is at least one candidate when filtering TCP ones
|
|
@@ -769,21 +936,35 @@ ColibriFocus.prototype.sendIceCandidates = function (candidates) {
|
769
|
936
|
mycands.c('conference', {xmlns: 'http://jitsi.org/protocol/colibri', id: this.confid});
|
770
|
937
|
// FIXME: multi-candidate logic is taken from strophe.jingle, should be refactored there
|
771
|
938
|
var localSDP = new SDP(this.peerconnection.localDescription.sdp);
|
772
|
|
- for (var mid = 0; mid < localSDP.media.length; mid++) {
|
|
939
|
+ for (var mid = 0; mid < localSDP.media.length; mid++)
|
|
940
|
+ {
|
773
|
941
|
var cands = candidates.filter(function (el) { return el.sdpMLineIndex == mid; });
|
774
|
|
- if (cands.length > 0) {
|
775
|
|
- mycands.c('content', {name: cands[0].sdpMid });
|
776
|
|
- mycands.c('channel', {
|
777
|
|
- id: $(this.mychannel[cands[0].sdpMLineIndex]).attr('id'),
|
778
|
|
- endpoint: $(this.mychannel[cands[0].sdpMLineIndex]).attr('endpoint'),
|
779
|
|
- expire: '15'
|
780
|
|
- });
|
|
942
|
+ if (cands.length > 0)
|
|
943
|
+ {
|
|
944
|
+ var name = cands[0].sdpMid;
|
|
945
|
+ mycands.c('content', {name: name });
|
|
946
|
+ if (name !== 'data')
|
|
947
|
+ {
|
|
948
|
+ mycands.c('channel', {
|
|
949
|
+ id: $(this.mychannel[cands[0].sdpMLineIndex]).attr('id'),
|
|
950
|
+ endpoint: $(this.mychannel[cands[0].sdpMLineIndex]).attr('endpoint'),
|
|
951
|
+ expire: self.channelExpire
|
|
952
|
+ });
|
|
953
|
+ }
|
|
954
|
+ else
|
|
955
|
+ {
|
|
956
|
+ mycands.c('sctpconnection', {
|
|
957
|
+ endpoint: $(this.mychannel[cands[0].sdpMLineIndex]).attr('endpoint'),
|
|
958
|
+ port: $(this.mychannel[cands[0].sdpMLineIndex]).attr('port'),
|
|
959
|
+ expire: self.channelExpire
|
|
960
|
+ });
|
|
961
|
+ }
|
781
|
962
|
mycands.c('transport', {xmlns: 'urn:xmpp:jingle:transports:ice-udp:1'});
|
782
|
963
|
for (var i = 0; i < cands.length; i++) {
|
783
|
964
|
mycands.c('candidate', SDPUtil.candidateToJingle(cands[i].candidate)).up();
|
784
|
965
|
}
|
785
|
966
|
mycands.up(); // transport
|
786
|
|
- mycands.up(); // channel
|
|
967
|
+ mycands.up(); // channel / sctpconnection
|
787
|
968
|
mycands.up(); // content
|
788
|
969
|
}
|
789
|
970
|
}
|
|
@@ -814,13 +995,26 @@ ColibriFocus.prototype.terminate = function (session, reason) {
|
814
|
995
|
var change = $iq({to: this.bridgejid, type: 'set'});
|
815
|
996
|
change.c('conference', {xmlns: 'http://jitsi.org/protocol/colibri', id: this.confid});
|
816
|
997
|
for (var channel = 0; channel < this.channels[participant].length; channel++) {
|
817
|
|
- change.c('content', {name: channel === 0 ? 'audio' : 'video'});
|
818
|
|
- change.c('channel', {
|
819
|
|
- id: $(this.channels[participant][channel]).attr('id'),
|
820
|
|
- endpoint: $(this.channels[participant][channel]).attr('endpoint'),
|
821
|
|
- expire: '0'
|
822
|
|
- });
|
823
|
|
- change.up(); // end of channel
|
|
998
|
+ var name = channel === 0 ? 'audio' : 'video';
|
|
999
|
+ if (channel == 2)
|
|
1000
|
+ name = 'data';
|
|
1001
|
+ change.c('content', {name: name});
|
|
1002
|
+ if (name !== 'data')
|
|
1003
|
+ {
|
|
1004
|
+ change.c('channel', {
|
|
1005
|
+ id: $(this.channels[participant][channel]).attr('id'),
|
|
1006
|
+ endpoint: $(this.channels[participant][channel]).attr('endpoint'),
|
|
1007
|
+ expire: '0'
|
|
1008
|
+ });
|
|
1009
|
+ }
|
|
1010
|
+ else
|
|
1011
|
+ {
|
|
1012
|
+ change.c('sctpconnection', {
|
|
1013
|
+ endpoint: $(this.channels[participant][channel]).attr('endpoint'),
|
|
1014
|
+ expire: '0'
|
|
1015
|
+ });
|
|
1016
|
+ }
|
|
1017
|
+ change.up(); // end of channel/sctpconnection
|
824
|
1018
|
change.up(); // end of content
|
825
|
1019
|
}
|
826
|
1020
|
this.connection.sendIQ(change,
|