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

SDPDiffer.js 5.8KB

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