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

SDPDiffer.js 5.7KB

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