|
@@ -1038,7 +1038,9 @@ JingleSessionPC.prototype.addStream = function (stream, callback, ssrcInfo) {
|
1038
|
1038
|
if(this.peerconnection.localDescription) {
|
1039
|
1039
|
oldSdp = new SDP(this.peerconnection.localDescription.sdp);
|
1040
|
1040
|
}
|
1041
|
|
- if(stream)
|
|
1041
|
+ //when adding muted stream we have to pass the ssrcInfo but we don't
|
|
1042
|
+ //have a stream
|
|
1043
|
+ if(stream || ssrcInfo)
|
1042
|
1044
|
this.peerconnection.addStream(stream, ssrcInfo);
|
1043
|
1045
|
}
|
1044
|
1046
|
|
|
@@ -1054,7 +1056,8 @@ JingleSessionPC.prototype.addStream = function (stream, callback, ssrcInfo) {
|
1054
|
1056
|
logger.log('modify sources done');
|
1055
|
1057
|
|
1056
|
1058
|
callback();
|
1057
|
|
- if(ssrcInfo) { //available only on video unmute
|
|
1059
|
+ if(ssrcInfo) {
|
|
1060
|
+ //available only on video unmute or when adding muted stream
|
1058
|
1061
|
self.modifiedSSRCs[ssrcInfo.type] =
|
1059
|
1062
|
self.modifiedSSRCs[ssrcInfo.type] || [];
|
1060
|
1063
|
self.modifiedSSRCs[ssrcInfo.type].push(ssrcInfo);
|
|
@@ -1065,6 +1068,15 @@ JingleSessionPC.prototype.addStream = function (stream, callback, ssrcInfo) {
|
1065
|
1068
|
});
|
1066
|
1069
|
}
|
1067
|
1070
|
|
|
1071
|
+/**
|
|
1072
|
+ * Generate ssrc info object for a stream with the following properties:
|
|
1073
|
+ * - ssrcs - Array of the ssrcs associated with the stream.
|
|
1074
|
+ * - groups - Array of the groups associated with the stream.
|
|
1075
|
+ */
|
|
1076
|
+JingleSessionPC.prototype.generateNewStreamSSRCInfo = function () {
|
|
1077
|
+ return this.peerconnection.generateNewStreamSSRCInfo();
|
|
1078
|
+};
|
|
1079
|
+
|
1068
|
1080
|
/**
|
1069
|
1081
|
* Remove streams.
|
1070
|
1082
|
* @param stream stream that will be removed.
|
|
@@ -1420,6 +1432,38 @@ JingleSessionPC.prototype.fixSourceAddJingle = function (jingle) {
|
1420
|
1432
|
});
|
1421
|
1433
|
});
|
1422
|
1434
|
}
|
|
1435
|
+
|
|
1436
|
+ ssrcs = this.modifiedSSRCs["addMuted"];
|
|
1437
|
+ this.modifiedSSRCs["addMuted"] = [];
|
|
1438
|
+ if(ssrcs && ssrcs.length) {
|
|
1439
|
+ ssrcs.forEach(function (ssrcObj) {
|
|
1440
|
+ var desc = createDescriptionNode(jingle, ssrcObj.mtype);
|
|
1441
|
+ var cname = Math.random().toString(36).substring(2);
|
|
1442
|
+ ssrcObj.ssrc.ssrcs.forEach(function (ssrc) {
|
|
1443
|
+ var sourceNode = desc.find(">source[ssrc=\"" +ssrc + "\"]");
|
|
1444
|
+ sourceNode.remove();
|
|
1445
|
+ var sourceXML = "<source " +
|
|
1446
|
+ "xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\" ssrc=\"" +
|
|
1447
|
+ ssrc + "\">" +
|
|
1448
|
+ "<parameter xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"" +
|
|
1449
|
+ " value=\"" + ssrcObj.msid + "\" name=\"msid\"/>" +
|
|
1450
|
+ "<parameter xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"" +
|
|
1451
|
+ " value=\"" + cname + "\" name=\"cname\" />" + "</source>";
|
|
1452
|
+ desc.append(sourceXML);
|
|
1453
|
+ });
|
|
1454
|
+ ssrcObj.ssrc.groups.forEach(function (group) {
|
|
1455
|
+ var groupNode = desc.find(">ssrc-group[semantics=\"" +
|
|
1456
|
+ group.group.semantics + "\"]:has(source[ssrc=\"" + group.primarySSRC +
|
|
1457
|
+ "\"])");
|
|
1458
|
+ groupNode.remove();
|
|
1459
|
+ desc.append("<ssrc-group semantics=\"" +
|
|
1460
|
+ group.group.semantics +
|
|
1461
|
+ "\" xmlns=\"urn:xmpp:jingle:apps:rtp:ssma:0\"><source ssrc=\"" +
|
|
1462
|
+ group.group.ssrcs.split(" ").join("\"/><source ssrc=\"") + "\"/>" +
|
|
1463
|
+ "</ssrc-group>");
|
|
1464
|
+ });
|
|
1465
|
+ });
|
|
1466
|
+ }
|
1423
|
1467
|
}
|
1424
|
1468
|
|
1425
|
1469
|
/**
|
|
@@ -1452,24 +1496,7 @@ JingleSessionPC.prototype.fixSourceRemoveJingle = function(jingle) {
|
1452
|
1496
|
this.modifiedSSRCs["remove"] = [];
|
1453
|
1497
|
if(ssrcs && ssrcs.length)
|
1454
|
1498
|
ssrcs.forEach(function (ssrcObj) {
|
1455
|
|
- var content = $(jingle.tree()).find(">jingle>content[name=\"" +
|
1456
|
|
- ssrcObj.mtype + "\"]");
|
1457
|
|
-
|
1458
|
|
- if(!content || !content.length) {
|
1459
|
|
- $(jingle.tree()).find(">jingle").append(
|
1460
|
|
- "<content name=\"" + ssrcObj.mtype + "\"></content>");
|
1461
|
|
- content = $(jingle.tree()).find(">jingle>content[name=\"" +
|
1462
|
|
- ssrcObj.mtype + "\"]");
|
1463
|
|
- }
|
1464
|
|
-
|
1465
|
|
- var desc = content.find(">description");
|
1466
|
|
- if(!desc || !desc.length) {
|
1467
|
|
- content.append("<description " +
|
1468
|
|
- "xmlns=\"urn:xmpp:jingle:apps:rtp:1\" media=\"" +
|
1469
|
|
- ssrcObj.mtype + "\"></description>");
|
1470
|
|
- desc = content.find(">description");
|
1471
|
|
- }
|
1472
|
|
-
|
|
1499
|
+ var desc = createDescriptionNode(jingle, ssrcObj.mtype);
|
1473
|
1500
|
ssrcObj.ssrc.ssrcs.forEach(function (ssrc) {
|
1474
|
1501
|
var sourceNode = desc.find(">source[ssrc=\"" +ssrc + "\"]");
|
1475
|
1502
|
if(!sourceNode || !sourceNode.length) {
|
|
@@ -1494,4 +1521,31 @@ JingleSessionPC.prototype.fixSourceRemoveJingle = function(jingle) {
|
1494
|
1521
|
});
|
1495
|
1522
|
}
|
1496
|
1523
|
|
|
1524
|
+/**
|
|
1525
|
+ * Returns the description node related to the passed content type. If the node
|
|
1526
|
+ * doesn't exists it will be created.
|
|
1527
|
+ * @param jingle - the jingle packet
|
|
1528
|
+ * @param mtype - the content type(audio, video, etc.)
|
|
1529
|
+ */
|
|
1530
|
+function createDescriptionNode(jingle, mtype) {
|
|
1531
|
+ var content = $(jingle.tree()).find(">jingle>content[name=\"" +
|
|
1532
|
+ mtype + "\"]");
|
|
1533
|
+
|
|
1534
|
+ if(!content || !content.length) {
|
|
1535
|
+ $(jingle.tree()).find(">jingle").append(
|
|
1536
|
+ "<content name=\"" + mtype + "\"></content>");
|
|
1537
|
+ content = $(jingle.tree()).find(">jingle>content[name=\"" +
|
|
1538
|
+ mtype + "\"]");
|
|
1539
|
+ }
|
|
1540
|
+
|
|
1541
|
+ var desc = content.find(">description");
|
|
1542
|
+ if(!desc || !desc.length) {
|
|
1543
|
+ content.append("<description " +
|
|
1544
|
+ "xmlns=\"urn:xmpp:jingle:apps:rtp:1\" media=\"" +
|
|
1545
|
+ mtype + "\"></description>");
|
|
1546
|
+ desc = content.find(">description");
|
|
1547
|
+ }
|
|
1548
|
+ return desc;
|
|
1549
|
+}
|
|
1550
|
+
|
1497
|
1551
|
module.exports = JingleSessionPC;
|