您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

SDPDiffer.js 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. function SDPDiffer(mySDP, otherSDP) {
  2. this.mySDP = mySDP;
  3. this.otherSDP = otherSDP;
  4. }
  5. /**
  6. * Returns map of MediaChannel that contains only media not contained in <tt>otherSdp</tt>. Mapped by channel idx.
  7. * @param otherSdp the other SDP to check ssrc with.
  8. */
  9. SDPDiffer.prototype.getNewMedia = function() {
  10. // this could be useful in Array.prototype.
  11. function arrayEquals(array) {
  12. // if the other array is a falsy value, return
  13. if (!array)
  14. return false;
  15. // compare lengths - can save a lot of time
  16. if (this.length != array.length)
  17. return false;
  18. for (var i = 0, l=this.length; i < l; i++) {
  19. // Check if we have nested arrays
  20. if (this[i] instanceof Array && array[i] instanceof Array) {
  21. // recurse into the nested arrays
  22. if (!this[i].equals(array[i]))
  23. return false;
  24. }
  25. else if (this[i] != array[i]) {
  26. // Warning - two different object instances will never be equal: {x:20} != {x:20}
  27. return false;
  28. }
  29. }
  30. return true;
  31. }
  32. var myMedias = this.mySDP.getMediaSsrcMap();
  33. var othersMedias = this.otherSDP.getMediaSsrcMap();
  34. var newMedia = {};
  35. Object.keys(othersMedias).forEach(function(othersMediaIdx) {
  36. var myMedia = myMedias[othersMediaIdx];
  37. var othersMedia = othersMedias[othersMediaIdx];
  38. if(!myMedia && othersMedia) {
  39. // Add whole channel
  40. newMedia[othersMediaIdx] = othersMedia;
  41. return;
  42. }
  43. // Look for new ssrcs accross the channel
  44. Object.keys(othersMedia.ssrcs).forEach(function(ssrc) {
  45. if(Object.keys(myMedia.ssrcs).indexOf(ssrc) === -1) {
  46. // Allocate channel if we've found ssrc that doesn't exist in our channel
  47. if(!newMedia[othersMediaIdx]){
  48. newMedia[othersMediaIdx] = {
  49. mediaindex: othersMedia.mediaindex,
  50. mid: othersMedia.mid,
  51. ssrcs: {},
  52. ssrcGroups: []
  53. };
  54. }
  55. newMedia[othersMediaIdx].ssrcs[ssrc] = othersMedia.ssrcs[ssrc];
  56. }
  57. });
  58. // Look for new ssrc groups across the channels
  59. othersMedia.ssrcGroups.forEach(function(otherSsrcGroup){
  60. // try to match the other ssrc-group with an ssrc-group of ours
  61. var matched = false;
  62. for (var i = 0; i < myMedia.ssrcGroups.length; i++) {
  63. var mySsrcGroup = myMedia.ssrcGroups[i];
  64. if (otherSsrcGroup.semantics == mySsrcGroup.semantics
  65. && arrayEquals.apply(otherSsrcGroup.ssrcs, [mySsrcGroup.ssrcs])) {
  66. matched = true;
  67. break;
  68. }
  69. }
  70. if (!matched) {
  71. // Allocate channel if we've found an ssrc-group that doesn't
  72. // exist in our channel
  73. if(!newMedia[othersMediaIdx]){
  74. newMedia[othersMediaIdx] = {
  75. mediaindex: othersMedia.mediaindex,
  76. mid: othersMedia.mid,
  77. ssrcs: {},
  78. ssrcGroups: []
  79. };
  80. }
  81. newMedia[othersMediaIdx].ssrcGroups.push(otherSsrcGroup);
  82. }
  83. });
  84. });
  85. return newMedia;
  86. };
  87. /**
  88. * Sends SSRC update IQ.
  89. * @param sdpMediaSsrcs SSRCs map obtained from SDP.getNewMedia. Cntains SSRCs to add/remove.
  90. * @param sid session identifier that will be put into the IQ.
  91. * @param initiator initiator identifier.
  92. * @param toJid destination Jid
  93. * @param isAdd indicates if this is remove or add operation.
  94. */
  95. SDPDiffer.prototype.toJingle = function(modify) {
  96. var sdpMediaSsrcs = this.getNewMedia();
  97. var self = this;
  98. // FIXME: only announce video ssrcs since we mix audio and dont need
  99. // the audio ssrcs therefore
  100. var modified = false;
  101. Object.keys(sdpMediaSsrcs).forEach(function(mediaindex){
  102. modified = true;
  103. var media = sdpMediaSsrcs[mediaindex];
  104. modify.c('content', {name: media.mid});
  105. modify.c('description', {xmlns:'urn:xmpp:jingle:apps:rtp:1', media: media.mid});
  106. // FIXME: not completly sure this operates on blocks and / or handles different ssrcs correctly
  107. // generate sources from lines
  108. Object.keys(media.ssrcs).forEach(function(ssrcNum) {
  109. var mediaSsrc = media.ssrcs[ssrcNum];
  110. modify.c('source', { xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
  111. modify.attrs({ssrc: mediaSsrc.ssrc});
  112. // iterate over ssrc lines
  113. mediaSsrc.lines.forEach(function (line) {
  114. var idx = line.indexOf(' ');
  115. var kv = line.substr(idx + 1);
  116. modify.c('parameter');
  117. if (kv.indexOf(':') == -1) {
  118. modify.attrs({ name: kv });
  119. } else {
  120. modify.attrs({ name: kv.split(':', 2)[0] });
  121. modify.attrs({ value: kv.split(':', 2)[1] });
  122. }
  123. modify.up(); // end of parameter
  124. });
  125. modify.up(); // end of source
  126. });
  127. // generate source groups from lines
  128. media.ssrcGroups.forEach(function(ssrcGroup) {
  129. if (ssrcGroup.ssrcs.length != 0) {
  130. modify.c('ssrc-group', {
  131. semantics: ssrcGroup.semantics,
  132. xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0'
  133. });
  134. ssrcGroup.ssrcs.forEach(function (ssrc) {
  135. modify.c('source', { ssrc: ssrc })
  136. .up(); // end of source
  137. });
  138. modify.up(); // end of ssrc-group
  139. }
  140. });
  141. modify.up(); // end of description
  142. modify.up(); // end of content
  143. });
  144. return modified;
  145. };
  146. module.exports = SDPDiffer;