Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

SDPDiffer.js 6.8KB

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