Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

SDPDiffer.js 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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. if (!mySDP) {
  41. throw new Error('"mySDP" is undefined!');
  42. } else if (!otherSDP) {
  43. throw new Error('"otherSDP" is undefined!');
  44. }
  45. }
  46. /**
  47. * Returns map of MediaChannel that contains media contained in
  48. * 'mySDP', but not contained in 'otherSdp'. Mapped by channel idx.
  49. */
  50. SDPDiffer.prototype.getNewMedia = function() {
  51. const myMedias = this.mySDP.getMediaSsrcMap();
  52. const othersMedias = this.otherSDP.getMediaSsrcMap();
  53. const newMedia = {};
  54. Object.keys(othersMedias).forEach(othersMediaIdx => {
  55. const myMedia = myMedias[othersMediaIdx];
  56. const othersMedia = othersMedias[othersMediaIdx];
  57. if (!myMedia && othersMedia) {
  58. // Add whole channel
  59. newMedia[othersMediaIdx] = othersMedia;
  60. return;
  61. }
  62. // Look for new ssrcs across the channel
  63. Object.keys(othersMedia.ssrcs).forEach(ssrc => {
  64. if (Object.keys(myMedia.ssrcs).indexOf(ssrc) === -1) {
  65. // Allocate channel if we've found ssrc that doesn't exist in
  66. // our channel
  67. if (!newMedia[othersMediaIdx]) {
  68. newMedia[othersMediaIdx] = {
  69. mediaindex: othersMedia.mediaindex,
  70. mid: othersMedia.mid,
  71. ssrcs: {},
  72. ssrcGroups: []
  73. };
  74. }
  75. newMedia[othersMediaIdx].ssrcs[ssrc] = othersMedia.ssrcs[ssrc];
  76. }
  77. });
  78. // Look for new ssrc groups across the channels
  79. othersMedia.ssrcGroups.forEach(otherSsrcGroup => {
  80. // try to match the other ssrc-group with an ssrc-group of ours
  81. let matched = false;
  82. for (let i = 0; i < myMedia.ssrcGroups.length; i++) {
  83. const mySsrcGroup = myMedia.ssrcGroups[i];
  84. if (otherSsrcGroup.semantics === mySsrcGroup.semantics
  85. && arrayEquals(otherSsrcGroup.ssrcs, mySsrcGroup.ssrcs)) {
  86. matched = true;
  87. break;
  88. }
  89. }
  90. if (!matched) {
  91. // Allocate channel if we've found an ssrc-group that doesn't
  92. // exist in our channel
  93. if (!newMedia[othersMediaIdx]) {
  94. newMedia[othersMediaIdx] = {
  95. mediaindex: othersMedia.mediaindex,
  96. mid: othersMedia.mid,
  97. ssrcs: {},
  98. ssrcGroups: []
  99. };
  100. }
  101. newMedia[othersMediaIdx].ssrcGroups.push(otherSsrcGroup);
  102. }
  103. });
  104. });
  105. return newMedia;
  106. };
  107. /**
  108. * TODO: document!
  109. */
  110. SDPDiffer.prototype.toJingle = function(modify) {
  111. const sdpMediaSsrcs = this.getNewMedia();
  112. let modified = false;
  113. Object.keys(sdpMediaSsrcs).forEach(mediaindex => {
  114. modified = true;
  115. const media = sdpMediaSsrcs[mediaindex];
  116. modify.c('content', { name: media.mid });
  117. modify.c('description',
  118. { xmlns: 'urn:xmpp:jingle:apps:rtp:1',
  119. media: media.mid });
  120. // FIXME: not completely sure this operates on blocks and / or handles
  121. // different ssrcs correctly
  122. // generate sources from lines
  123. Object.keys(media.ssrcs).forEach(ssrcNum => {
  124. const mediaSsrc = media.ssrcs[ssrcNum];
  125. modify.c('source', { xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
  126. modify.attrs({ ssrc: mediaSsrc.ssrc });
  127. // iterate over ssrc lines
  128. mediaSsrc.lines.forEach(line => {
  129. const idx = line.indexOf(' ');
  130. const kv = line.substr(idx + 1);
  131. modify.c('parameter');
  132. if (kv.indexOf(':') === -1) {
  133. modify.attrs({ name: kv });
  134. } else {
  135. const nv = kv.split(':', 2);
  136. const name = nv[0];
  137. const value = SDPUtil.filterSpecialChars(nv[1]);
  138. modify.attrs({ name });
  139. modify.attrs({ value });
  140. }
  141. modify.up(); // end of parameter
  142. });
  143. modify.up(); // end of source
  144. });
  145. // generate source groups from lines
  146. media.ssrcGroups.forEach(ssrcGroup => {
  147. if (ssrcGroup.ssrcs.length) {
  148. modify.c('ssrc-group', {
  149. semantics: ssrcGroup.semantics,
  150. xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0'
  151. });
  152. ssrcGroup.ssrcs.forEach(ssrc => {
  153. modify.c('source', { ssrc })
  154. .up(); // end of source
  155. });
  156. modify.up(); // end of ssrc-group
  157. }
  158. });
  159. modify.up(); // end of description
  160. modify.up(); // end of content
  161. });
  162. return modified;
  163. };