diff --git a/libs/strophe/strophe.jingle.sdp.js b/libs/strophe/strophe.jingle.sdp.js
index e9e9ff61b2..4a6b7ed349 100644
--- a/libs/strophe/strophe.jingle.sdp.js
+++ b/libs/strophe/strophe.jingle.sdp.js
@@ -17,27 +17,37 @@ function SDP(sdp) {
SDP.prototype.getMediaSsrcMap = function() {
var self = this;
var media_ssrcs = {};
- for (channelNum = 0; channelNum < self.media.length; channelNum++) {
- modified = true;
- tmp = SDPUtil.find_lines(self.media[channelNum], 'a=ssrc:');
- var type = SDPUtil.parse_mid(SDPUtil.find_line(self.media[channelNum], 'a=mid:'));
- var channel = new MediaChannel(channelNum, type);
- media_ssrcs[channelNum] = channel;
+ var tmp;
+ for (var mediaindex = 0; mediaindex < self.media.length; mediaindex++) {
+ tmp = SDPUtil.find_lines(self.media[mediaindex], 'a=ssrc:');
+ var mid = SDPUtil.parse_mid(SDPUtil.find_line(self.media[mediaindex], 'a=mid:'));
+ var media = {
+ mediaindex: mediaindex,
+ mid: mid,
+ ssrcs: {},
+ ssrcGroups: []
+ };
+ media_ssrcs[mediaindex] = media;
tmp.forEach(function (line) {
var linessrc = line.substring(7).split(' ')[0];
// allocate new ChannelSsrc
- if(!channel.ssrcs[linessrc]) {
- channel.ssrcs[linessrc] = new ChannelSsrc(linessrc, type);
+ if(!media.ssrcs[linessrc]) {
+ media.ssrcs[linessrc] = {
+ ssrc: linessrc,
+ lines: []
+ };
}
- channel.ssrcs[linessrc].lines.push(line);
+ media.ssrcs[linessrc].lines.push(line);
});
- tmp = SDPUtil.find_lines(self.media[channelNum], 'a=ssrc-group:');
+ tmp = SDPUtil.find_lines(self.media[mediaindex], 'a=ssrc-group:');
tmp.forEach(function(line){
var semantics = line.substr(0, idx).substr(13);
var ssrcs = line.substr(14 + semantics.length).split(' ');
if (ssrcs.length != 0) {
- var ssrcGroup = new ChannelSsrcGroup(semantics, ssrcs);
- channel.ssrcGroups.push(ssrcGroup);
+ media.ssrcGroups.push({
+ semantics: semantics,
+ ssrcs: ssrcs
+ });
}
});
}
@@ -49,23 +59,28 @@ SDP.prototype.getMediaSsrcMap = function() {
* @returns {boolean} true if this SDP contains given SSRC.
*/
SDP.prototype.containsSSRC = function(ssrc) {
- var channels = this.getMediaSsrcMap();
+ var medias = this.getMediaSsrcMap();
var contains = false;
- Object.keys(channels).forEach(function(chNumber){
- var channel = channels[chNumber];
+ Object.keys(medias).forEach(function(mediaindex){
+ var media = medias[mediaindex];
//console.log("Check", channel, ssrc);
- if(Object.keys(channel.ssrcs).indexOf(ssrc) != -1){
+ if(Object.keys(media.ssrcs).indexOf(ssrc) != -1){
contains = true;
}
});
return contains;
};
+function SDPDiffer(mySDP, otherSDP) {
+ this.mySDP = new SDP(mySDP);
+ this.otherSDP = new SDP(otherSDP);
+}
+
/**
* Returns map of MediaChannel that contains only media not contained in otherSdp. Mapped by channel idx.
* @param otherSdp the other SDP to check ssrc with.
*/
-SDP.prototype.getNewMedia = function(otherSdp) {
+SDPDiffer.prototype.getNewMedia = function() {
// this could be useful in Array.prototype.
function arrayEquals(array) {
@@ -92,35 +107,40 @@ SDP.prototype.getNewMedia = function(otherSdp) {
return true;
}
- var myMedia = this.getMediaSsrcMap();
- var othersMedia = otherSdp.getMediaSsrcMap();
+ var myMedias = this.mySDP.getMediaSsrcMap();
+ var othersMedias = this.otherSDP.getMediaSsrcMap();
var newMedia = {};
- Object.keys(othersMedia).forEach(function(channelNum) {
- var myChannel = myMedia[channelNum];
- var othersChannel = othersMedia[channelNum];
- if(!myChannel && othersChannel) {
+ Object.keys(othersMedias).forEach(function(othersMediaIdx) {
+ var myMedia = myMedias[othersMediaIdx];
+ var othersMedia = othersMedias[othersMediaIdx];
+ if(!myMedia && othersMedia) {
// Add whole channel
- newMedia[channelNum] = othersChannel;
+ newMedia[othersMediaIdx] = othersMedia;
return;
}
// Look for new ssrcs accross the channel
- Object.keys(othersChannel.ssrcs).forEach(function(ssrc) {
- if(Object.keys(myChannel.ssrcs).indexOf(ssrc) === -1) {
+ Object.keys(othersMedia.ssrcs).forEach(function(ssrc) {
+ if(Object.keys(myMedia.ssrcs).indexOf(ssrc) === -1) {
// Allocate channel if we've found ssrc that doesn't exist in our channel
- if(!newMedia[channelNum]){
- newMedia[channelNum] = new MediaChannel(othersChannel.chNumber, othersChannel.mediaType);
+ if(!newMedia[othersMediaIdx]){
+ newMedia[othersMediaIdx] = {
+ mediaindex: othersMedia.mediaindex,
+ mid: othersMedia.mid,
+ ssrcs: {},
+ ssrcGroups: []
+ };
}
- newMedia[channelNum].ssrcs[ssrc] = othersChannel.ssrcs[ssrc];
+ newMedia[othersMediaIdx].ssrcs[ssrc] = othersMedia.ssrcs[ssrc];
}
});
// Look for new ssrc groups across the channels
- othersChannel.ssrcGroups.forEach(function(otherSsrcGroup){
+ othersMedia.ssrcGroups.forEach(function(otherSsrcGroup){
// try to match the other ssrc-group with an ssrc-group of ours
var matched = false;
- for (var i = 0; i < myChannel.ssrcGroups.length; i++) {
- var mySsrcGroup = myChannel.ssrcGroups[i];
+ for (var i = 0; i < myMedia.ssrcGroups.length; i++) {
+ var mySsrcGroup = myMedia.ssrcGroups[i];
if (otherSsrcGroup.semantics == mySsrcGroup.semantics
&& arrayEquals.apply(otherSsrcGroup.ssrcs, [mySsrcGroup.ssrcs])) {
@@ -133,16 +153,88 @@ SDP.prototype.getNewMedia = function(otherSdp) {
// Allocate channel if we've found an ssrc-group that doesn't
// exist in our channel
- if(!newMedia[channelNum]){
- newMedia[channelNum] = new MediaChannel(othersChannel.chNumber, othersChannel.mediaType);
+ if(!newMedia[othersMediaIdx]){
+ newMedia[othersMediaIdx] = {
+ mediaindex: othersMedia.mediaindex,
+ mid: othersMedia.mid,
+ ssrcs: {},
+ ssrcGroups: []
+ };
}
- newMedia[channelNum].ssrcGroups.push(otherSsrcGroup);
+ newMedia[othersMediaIdx].ssrcGroups.push(otherSsrcGroup);
}
});
});
return newMedia;
};
+/**
+ * Sends SSRC update IQ.
+ * @param sdpMediaSsrcs SSRCs map obtained from SDP.getNewMedia. Cntains SSRCs to add/remove.
+ * @param sid session identifier that will be put into the IQ.
+ * @param initiator initiator identifier.
+ * @param toJid destination Jid
+ * @param isAdd indicates if this is remove or add operation.
+ */
+SDPDiffer.prototype.toJingle = function(modify) {
+ var sdpMediaSsrcs = this.getNewMedia();
+ var self = this;
+
+ // FIXME: only announce video ssrcs since we mix audio and dont need
+ // the audio ssrcs therefore
+ var modified = false;
+ Object.keys(sdpMediaSsrcs).forEach(function(mediaindex){
+ modified = true;
+ var media = sdpMediaSsrcs[mediaindex];
+ modify.c('content', {name: media.mid});
+
+ modify.c('description', {xmlns:'urn:xmpp:jingle:apps:rtp:1', media: media.mid});
+ // FIXME: not completly sure this operates on blocks and / or handles different ssrcs correctly
+ // generate sources from lines
+ Object.keys(media.ssrcs).forEach(function(ssrcNum) {
+ var mediaSsrc = media.ssrcs[ssrcNum];
+ modify.c('source', { xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
+ modify.attrs({ssrc: mediaSsrc.ssrc});
+ // iterate over ssrc lines
+ mediaSsrc.lines.forEach(function (line) {
+ var idx = line.indexOf(' ');
+ var kv = line.substr(idx + 1);
+ modify.c('parameter');
+ if (kv.indexOf(':') == -1) {
+ modify.attrs({ name: kv });
+ } else {
+ modify.attrs({ name: kv.split(':', 2)[0] });
+ modify.attrs({ value: kv.split(':', 2)[1] });
+ }
+ modify.up(); // end of parameter
+ });
+ modify.up(); // end of source
+ });
+
+ // generate source groups from lines
+ media.ssrcGroups.forEach(function(ssrcGroup) {
+ if (ssrcGroup.ssrcs.length != 0) {
+
+ modify.c('ssrc-group', {
+ semantics: ssrcGroup.semantics,
+ xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0'
+ });
+
+ ssrcGroup.ssrcs.forEach(function (ssrc) {
+ modify.c('source', { ssrc: ssrc })
+ .up(); // end of source
+ });
+ modify.up(); // end of ssrc-group
+ }
+ });
+
+ modify.up(); // end of description
+ modify.up(); // end of content
+ });
+
+ return modified;
+};
+
// remove iSAC and CN from SDP
SDP.prototype.mangle = function () {
var i, j, mline, lines, rtpmap, newdesc;
@@ -683,62 +775,6 @@ SDP.prototype.jingle2media = function (content) {
return media;
};
-/**
- * Contains utility classes used in SDP class.
- *
- */
-
-/**
- * Class holds a=ssrc lines and media type a=mid
- * @param ssrc synchronization source identifier number(a=ssrc lines from SDP)
- * @param type media type eg. "audio" or "video"(a=mid frm SDP)
- * @constructor
- */
-function ChannelSsrc(ssrc, type) {
- this.ssrc = ssrc;
- this.type = type;
- this.lines = [];
-}
-
-/**
- * Class holds a=ssrc-group: lines
- * @param semantics
- * @param ssrcs
- * @constructor
- */
-function ChannelSsrcGroup(semantics, ssrcs, line) {
- this.semantics = semantics;
- this.ssrcs = ssrcs;
-}
-
-/**
- * Helper class represents media channel. Is a container for ChannelSsrc, holds channel idx and media type.
- * @param channelNumber channel idx in SDP media array.
- * @param mediaType media type(a=mid)
- * @constructor
- */
-function MediaChannel(channelNumber, mediaType) {
- /**
- * SDP channel number
- * @type {*}
- */
- this.chNumber = channelNumber;
- /**
- * Channel media type(a=mid)
- * @type {*}
- */
- this.mediaType = mediaType;
- /**
- * The maps of ssrc numbers to ChannelSsrc objects.
- */
- this.ssrcs = {};
-
- /**
- * The array of ChannelSsrcGroup objects.
- * @type {Array}
- */
- this.ssrcGroups = [];
-}
SDPUtil = {
iceparams: function (mediadesc, sessiondesc) {
diff --git a/libs/strophe/strophe.jingle.session.js b/libs/strophe/strophe.jingle.session.js
index 4c7513bb05..31eac54a74 100644
--- a/libs/strophe/strophe.jingle.session.js
+++ b/libs/strophe/strophe.jingle.session.js
@@ -968,121 +968,57 @@ JingleSession.prototype.switchStreams = function (new_stream, oldStream, success
*/
JingleSession.prototype.notifyMySSRCUpdate = function (old_sdp, new_sdp) {
- var old_media = old_sdp.getMediaSsrcMap();
- var new_media = new_sdp.getMediaSsrcMap();
- //console.log("old/new medias: ", old_media, new_media);
-
- var toAdd = old_sdp.getNewMedia(new_sdp);
- var toRemove = new_sdp.getNewMedia(old_sdp);
- //console.log("to add", toAdd);
- //console.log("to remove", toRemove);
- if(Object.keys(toRemove).length > 0){
- this.sendSSRCUpdate(toRemove, null, false);
- }
- if(Object.keys(toAdd).length > 0){
- this.sendSSRCUpdate(toAdd, null, true);
- }
-};
-
-/**
- * Empty method that does nothing by default. It should send SSRC update IQs to session participants.
- * @param sdpMediaSsrcs array of
- * @param fromJid
- * @param isAdd
- */
-JingleSession.prototype.sendSSRCUpdate = function(sdpMediaSsrcs, fromJid, isAdd) {
- var self = this;
- console.log('tell', self.peerjid, 'about ' + (isadd ? 'new' : 'removed') + ' ssrcs from' + self.me);
-
if (!(this.peerconnection.signalingState == 'stable' && this.peerconnection.iceConnectionState == 'connected')){
console.log("Too early to send updates");
return;
}
- this.sendSSRCUpdateIq(sdpMediaSsrcs, self.sid, self.initiator, self.peerjid, isadd);
-}
-
-/**
- * Sends SSRC update IQ.
- * @param sdpMediaSsrcs SSRCs map obtained from SDP.getNewMedia. Cntains SSRCs to add/remove.
- * @param sid session identifier that will be put into the IQ.
- * @param initiator initiator identifier.
- * @param toJid destination Jid
- * @param isAdd indicates if this is remove or add operation.
- */
-JingleSession.prototype.sendSSRCUpdateIq = function(sdpMediaSsrcs, sid, initiator, toJid, isAdd) {
-
- var self = this;
- var modify = $iq({to: toJid, type: 'set'})
+ // send source-add IQ.
+ var sdpDiffer = new SDPDiffer(old_sdp, new_sdp);
+ var add = $iq({to: self.peerjid, type: 'set'})
.c('jingle', {
xmlns: 'urn:xmpp:jingle:1',
- action: isAdd ? 'source-add' : 'source-remove',
- initiator: initiator,
- sid: sid
+ action: 'source-add',
+ initiator: self.initiator,
+ sid: self.sid
}
);
- // FIXME: only announce video ssrcs since we mix audio and dont need
- // the audio ssrcs therefore
- var modified = false;
- Object.keys(sdpMediaSsrcs).forEach(function(channelNum){
- modified = true;
- var channel = sdpMediaSsrcs[channelNum];
- modify.c('content', {name: channel.mediaType});
-
- modify.c('description', {xmlns:'urn:xmpp:jingle:apps:rtp:1', media: channel.mediaType});
- // FIXME: not completly sure this operates on blocks and / or handles different ssrcs correctly
- // generate sources from lines
- Object.keys(channel.ssrcs).forEach(function(ssrcNum) {
- var mediaSsrc = channel.ssrcs[ssrcNum];
- modify.c('source', { xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
- modify.attrs({ssrc: mediaSsrc.ssrc});
- // iterate over ssrc lines
- mediaSsrc.lines.forEach(function (line) {
- var idx = line.indexOf(' ');
- var kv = line.substr(idx + 1);
- modify.c('parameter');
- if (kv.indexOf(':') == -1) {
- modify.attrs({ name: kv });
- } else {
- modify.attrs({ name: kv.split(':', 2)[0] });
- modify.attrs({ value: kv.split(':', 2)[1] });
- }
- modify.up(); // end of parameter
- });
- modify.up(); // end of source
- });
-
- // generate source groups from lines
- channel.ssrcGroups.forEach(function(ssrcGroup) {
- if (ssrcGroup.ssrcs.length != 0) {
-
- modify.c('ssrc-group', {
- semantics: ssrcGroup.semantics,
- xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0'
- });
-
- ssrcGroup.ssrcs.forEach(function (ssrc) {
- modify.c('source', { ssrc: ssrc })
- .up(); // end of source
- });
- modify.up(); // end of ssrc-group
+ var added = sdpDiffer.toJingle(add);
+ if (added) {
+ this.connection.sendIQ(add,
+ function (res) {
+ console.info('got add result', res);
+ },
+ function (err) {
+ console.error('got add error', err);
}
- });
+ );
+ } else {
+ console.log('addition not necessary');
+ }
- modify.up(); // end of description
- modify.up(); // end of content
- });
- if (modified) {
- self.connection.sendIQ(modify,
+ // send source-remove IQ.
+ sdpDiffer = new SDPDiffer(new_sdp, old_sdp);
+ var remove = $iq({to: self.peerjid, type: 'set'})
+ .c('jingle', {
+ xmlns: 'urn:xmpp:jingle:1',
+ action: 'source-remove',
+ initiator: self.initiator,
+ sid: self.sid
+ }
+ );
+ var removed = sdpDiffer.toJingle(remove);
+ if (removed) {
+ this.connection.sendIQ(remove,
function (res) {
- console.info('got modify result', res);
+ console.info('got remove result', res);
},
function (err) {
- console.error('got modify error', err);
+ console.error('got remove error', err);
}
);
} else {
- console.log('modification not necessary');
+ console.log('removal not necessary');
}
};