|
@@ -72,6 +72,7 @@ function ColibriFocus(connection, bridgejid) {
|
72
|
72
|
this.media = ['audio', 'video'];
|
73
|
73
|
|
74
|
74
|
this.connection.jingle.sessions[this.sid] = this;
|
|
75
|
+ this.bundledTransports = {};
|
75
|
76
|
this.mychannel = [];
|
76
|
77
|
this.channels = [];
|
77
|
78
|
this.remotessrc = {};
|
|
@@ -296,13 +297,20 @@ ColibriFocus.prototype._makeConference = function () {
|
296
|
297
|
|
297
|
298
|
elem.c(elemName, elemAttrs);
|
298
|
299
|
elem.attrs({ endpoint: self.myMucResource });
|
|
300
|
+ if (config.useBundle) {
|
|
301
|
+ elem.attrs({ 'channel-bundle-id': self.myMucResource });
|
|
302
|
+ }
|
299
|
303
|
elem.up();// end of channel/sctpconnection
|
300
|
304
|
|
301
|
305
|
for (var j = 0; j < self.peers.length; j++) {
|
302
|
306
|
var peer = self.peers[j];
|
|
307
|
+ var peerEndpoint = peer.substr(1 + peer.lastIndexOf('/'));
|
303
|
308
|
|
304
|
309
|
elem.c(elemName, elemAttrs);
|
305
|
|
- elem.attrs({ endpoint: peer.substr(1 + peer.lastIndexOf('/')) });
|
|
310
|
+ elem.attrs({ endpoint: peerEndpoint });
|
|
311
|
+ if (config.useBundle) {
|
|
312
|
+ elem.attrs({ 'channel-bundle-id': peerEndpoint });
|
|
313
|
+ }
|
306
|
314
|
elem.up(); // end of channel/sctpconnection
|
307
|
315
|
}
|
308
|
316
|
elem.up(); // end of content
|
|
@@ -353,7 +361,7 @@ ColibriFocus.prototype._makeConference = function () {
|
353
|
361
|
);
|
354
|
362
|
};
|
355
|
363
|
|
356
|
|
-// callback when a conference was created
|
|
364
|
+// callback when a colibri conference was created
|
357
|
365
|
ColibriFocus.prototype.createdConference = function (result) {
|
358
|
366
|
console.log('created a conference on the bridge');
|
359
|
367
|
var self = this;
|
|
@@ -379,6 +387,14 @@ ColibriFocus.prototype.createdConference = function (result) {
|
379
|
387
|
}
|
380
|
388
|
}
|
381
|
389
|
|
|
390
|
+ // save the 'transport' elements from 'channel-bundle'-s
|
|
391
|
+ var channelBundles = $(result).find('>conference>channel-bundle');
|
|
392
|
+ for (var i = 0; i < channelBundles.length; i++)
|
|
393
|
+ {
|
|
394
|
+ var endpointId = $(channelBundles[i]).attr('id');
|
|
395
|
+ this.bundledTransports[endpointId] = $(channelBundles[i]).find('>transport[xmlns="urn:xmpp:jingle:transports:ice-udp:1"]');
|
|
396
|
+ }
|
|
397
|
+
|
382
|
398
|
console.log('remote channels', this.channels);
|
383
|
399
|
|
384
|
400
|
// Notify that the focus has created the conference on the bridge
|
|
@@ -390,6 +406,11 @@ ColibriFocus.prototype.createdConference = function (result) {
|
390
|
406
|
's=-\r\n' +
|
391
|
407
|
't=0 0\r\n' +
|
392
|
408
|
/* Audio */
|
|
409
|
+ (config.useBundle
|
|
410
|
+ ? ('a=group:BUNDLE audio video' +
|
|
411
|
+ (config.openSctp ? ' data' : '') +
|
|
412
|
+ '\r\n')
|
|
413
|
+ : '') +
|
393
|
414
|
'm=audio 1 RTP/SAVPF 111 103 104 0 8 106 105 13 126\r\n' +
|
394
|
415
|
'c=IN IP4 0.0.0.0\r\n' +
|
395
|
416
|
'a=rtcp:1 IN IP4 0.0.0.0\r\n' +
|
|
@@ -490,7 +511,13 @@ ColibriFocus.prototype.createdConference = function (result) {
|
490
|
511
|
}
|
491
|
512
|
|
492
|
513
|
// FIXME: should take code from .fromJingle
|
493
|
|
- tmp = $(this.mychannel[channel]).find('>transport[xmlns="urn:xmpp:jingle:transports:ice-udp:1"]');
|
|
514
|
+ var channelBundleId = $(this.mychannel[channel]).attr('channel-bundle-id');
|
|
515
|
+ if (typeof channelBundleId != 'undefined') {
|
|
516
|
+ tmp = this.bundledTransports[channelBundleId];
|
|
517
|
+ } else {
|
|
518
|
+ tmp = $(this.mychannel[channel]).find('>transport[xmlns="urn:xmpp:jingle:transports:ice-udp:1"]');
|
|
519
|
+ }
|
|
520
|
+
|
494
|
521
|
if (tmp.length) {
|
495
|
522
|
bridgeSDP.media[channel] += 'a=ice-ufrag:' + tmp.attr('ufrag') + '\r\n';
|
496
|
523
|
bridgeSDP.media[channel] += 'a=ice-pwd:' + tmp.attr('pwd') + '\r\n';
|
|
@@ -514,7 +541,7 @@ ColibriFocus.prototype.createdConference = function (result) {
|
514
|
541
|
function (answer) {
|
515
|
542
|
self.peerconnection.setLocalDescription(answer,
|
516
|
543
|
function () {
|
517
|
|
- console.log('setLocalDescription succeded.');
|
|
544
|
+ console.log('setLocalDescription succeeded.');
|
518
|
545
|
// make sure our presence is updated
|
519
|
546
|
$(document).trigger('setLocalDescription.jingle', [self.sid]);
|
520
|
547
|
var elem = $iq({to: self.bridgejid, type: 'get'});
|
|
@@ -570,7 +597,7 @@ ColibriFocus.prototype.createdConference = function (result) {
|
570
|
597
|
},
|
571
|
598
|
function (error) {
|
572
|
599
|
console.error(
|
573
|
|
- "ERROR setLocalDescription succeded",
|
|
600
|
+ "ERROR sending colibri message",
|
574
|
601
|
error, elem);
|
575
|
602
|
}
|
576
|
603
|
);
|
|
@@ -616,7 +643,9 @@ ColibriFocus.prototype.initiate = function (peer, isInitiator) {
|
616
|
643
|
var localSDP = new SDP(this.peerconnection.localDescription.sdp);
|
617
|
644
|
// throw away stuff we don't want
|
618
|
645
|
// not needed with static offer
|
619
|
|
- sdp.removeSessionLines('a=group:');
|
|
646
|
+ if (!config.useBundle) {
|
|
647
|
+ sdp.removeSessionLines('a=group:');
|
|
648
|
+ }
|
620
|
649
|
sdp.removeSessionLines('a=msid-semantic:'); // FIXME: not mapped over jingle anyway...
|
621
|
650
|
for (var i = 0; i < sdp.media.length; i++) {
|
622
|
651
|
if (!config.useRtcpMux){
|
|
@@ -670,7 +699,14 @@ ColibriFocus.prototype.initiate = function (peer, isInitiator) {
|
670
|
699
|
sdp.media[j] += 'a=ssrc:' + '3735928559' + ' ' + 'mslabel:mixedmslabel' + '\r\n';
|
671
|
700
|
}
|
672
|
701
|
|
673
|
|
- tmp = chan.find('>transport[xmlns="urn:xmpp:jingle:transports:ice-udp:1"]');
|
|
702
|
+ // In the case of bundle, we add each candidate to all m= lines/jingle contents,
|
|
703
|
+ // just as chrome does
|
|
704
|
+ if (config.useBundle){
|
|
705
|
+ tmp = this.bundledTransports[chan.attr('channel-bundle-id')];
|
|
706
|
+ } else {
|
|
707
|
+ tmp = chan.find('>transport[xmlns="urn:xmpp:jingle:transports:ice-udp:1"]');
|
|
708
|
+ }
|
|
709
|
+
|
674
|
710
|
if (tmp.length) {
|
675
|
711
|
if (tmp.attr('ufrag'))
|
676
|
712
|
sdp.media[j] += 'a=ice-ufrag:' + tmp.attr('ufrag') + '\r\n';
|
|
@@ -757,12 +793,17 @@ ColibriFocus.prototype.addNewParticipant = function (peer) {
|
757
|
793
|
localSDP.media.forEach(function (media, channel) {
|
758
|
794
|
var name = SDPUtil.parse_mid(SDPUtil.find_line(media, 'a=mid:'));
|
759
|
795
|
var elemName;
|
|
796
|
+ var endpointId = peer.substr(1 + peer.lastIndexOf('/'));
|
760
|
797
|
var elemAttrs
|
761
|
798
|
= {
|
762
|
799
|
initiator: 'true',
|
763
|
800
|
expire: self.channelExpire,
|
764
|
|
- endpoint: peer.substr(1 + peer.lastIndexOf('/'))
|
|
801
|
+ endpoint: endpointId
|
765
|
802
|
};
|
|
803
|
+ if (config.useBundle) {
|
|
804
|
+ elemAttrs['channel-bundle-id'] = endpointId;
|
|
805
|
+ }
|
|
806
|
+
|
766
|
807
|
|
767
|
808
|
if ('data' == name)
|
768
|
809
|
{
|
|
@@ -785,7 +826,8 @@ ColibriFocus.prototype.addNewParticipant = function (peer) {
|
785
|
826
|
this.connection.sendIQ(elem,
|
786
|
827
|
function (result) {
|
787
|
828
|
var contents = $(result).find('>conference>content').get();
|
788
|
|
- for (var i = 0; i < contents.length; i++) {
|
|
829
|
+ var i;
|
|
830
|
+ for (i = 0; i < contents.length; i++) {
|
789
|
831
|
var channelXml = $(contents[i]).find('>channel');
|
790
|
832
|
if (channelXml.length)
|
791
|
833
|
{
|
|
@@ -797,6 +839,12 @@ ColibriFocus.prototype.addNewParticipant = function (peer) {
|
797
|
839
|
}
|
798
|
840
|
self.channels[index][i] = tmp[0];
|
799
|
841
|
}
|
|
842
|
+ var channelBundles = $(result).find('>conference>channel-bundle');
|
|
843
|
+ for (i = 0; i < channelBundles.length; i++)
|
|
844
|
+ {
|
|
845
|
+ var endpointId = $(channelBundles[i]).attr('id');
|
|
846
|
+ self.bundledTransports[endpointId] = $(channelBundles[i]).find('>transport[xmlns="urn:xmpp:jingle:transports:ice-udp:1"]');
|
|
847
|
+ }
|
800
|
848
|
self.initiate(peer, true);
|
801
|
849
|
},
|
802
|
850
|
function (error) {
|
|
@@ -1023,6 +1071,12 @@ ColibriFocus.prototype.addIceCandidate = function (session, elem) {
|
1023
|
1071
|
$(elem).each(function () {
|
1024
|
1072
|
var name = $(this).attr('name');
|
1025
|
1073
|
|
|
1074
|
+ // If we are using bundle, audio/video/data channel will have the same candidates, so only send them for
|
|
1075
|
+ // the audio channel.
|
|
1076
|
+ if (config.useBundle && name !== 'audio') {
|
|
1077
|
+ return;
|
|
1078
|
+ }
|
|
1079
|
+
|
1026
|
1080
|
var channel = name == 'audio' ? 0 : 1; // FIXME: search mlineindex in localdesc
|
1027
|
1081
|
if (name != 'audio' && name != 'video')
|
1028
|
1082
|
channel = 2; // name == 'data'
|