Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

SDPDiffer.js 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*
  2. * Copyright @ 2015 Atlassian Pty Ltd
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. function SDPDiffer(mySDP, otherSDP) {
  17. this.mySDP = mySDP;
  18. this.otherSDP = otherSDP;
  19. }
  20. /**
  21. * Returns map of MediaChannel that contains only media not contained in <tt>otherSdp</tt>. Mapped by channel idx.
  22. * @param otherSdp the other SDP to check ssrc with.
  23. */
  24. SDPDiffer.prototype.getNewMedia = function() {
  25. // this could be useful in Array.prototype.
  26. function arrayEquals(array) {
  27. // if the other array is a falsy value, return
  28. if (!array)
  29. return false;
  30. // compare lengths - can save a lot of time
  31. if (this.length != array.length)
  32. return false;
  33. for (var i = 0, l=this.length; i < l; i++) {
  34. // Check if we have nested arrays
  35. if (this[i] instanceof Array && array[i] instanceof Array) {
  36. // recurse into the nested arrays
  37. if (!this[i].equals(array[i]))
  38. return false;
  39. }
  40. else if (this[i] != array[i]) {
  41. // Warning - two different object instances will never be equal: {x:20} != {x:20}
  42. return false;
  43. }
  44. }
  45. return true;
  46. }
  47. var myMedias = this.mySDP.getMediaSsrcMap();
  48. var othersMedias = this.otherSDP.getMediaSsrcMap();
  49. var newMedia = {};
  50. Object.keys(othersMedias).forEach(function(othersMediaIdx) {
  51. var myMedia = myMedias[othersMediaIdx];
  52. var othersMedia = othersMedias[othersMediaIdx];
  53. if(!myMedia && othersMedia) {
  54. // Add whole channel
  55. newMedia[othersMediaIdx] = othersMedia;
  56. return;
  57. }
  58. // Look for new ssrcs accross the channel
  59. Object.keys(othersMedia.ssrcs).forEach(function(ssrc) {
  60. if(Object.keys(myMedia.ssrcs).indexOf(ssrc) === -1) {
  61. // Allocate channel if we've found ssrc that doesn't exist in 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(function(otherSsrcGroup){
  75. // try to match the other ssrc-group with an ssrc-group of ours
  76. var matched = false;
  77. for (var i = 0; i < myMedia.ssrcGroups.length; i++) {
  78. var mySsrcGroup = myMedia.ssrcGroups[i];
  79. if (otherSsrcGroup.semantics == mySsrcGroup.semantics
  80. && arrayEquals.apply(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. * Sends SSRC update IQ.
  104. * @param sdpMediaSsrcs SSRCs map obtained from SDP.getNewMedia. Cntains SSRCs to add/remove.
  105. * @param sid session identifier that will be put into the IQ.
  106. * @param initiator initiator identifier.
  107. * @param toJid destination Jid
  108. * @param isAdd indicates if this is remove or add operation.
  109. */
  110. SDPDiffer.prototype.toJingle = function(modify) {
  111. var sdpMediaSsrcs = this.getNewMedia();
  112. var self = this;
  113. // FIXME: only announce video ssrcs since we mix audio and dont need
  114. // the audio ssrcs therefore
  115. var modified = false;
  116. Object.keys(sdpMediaSsrcs).forEach(function(mediaindex){
  117. modified = true;
  118. var media = sdpMediaSsrcs[mediaindex];
  119. modify.c('content', {name: media.mid});
  120. modify.c('description', {xmlns:'urn:xmpp:jingle:apps:rtp:1', media: media.mid});
  121. // FIXME: not completly sure this operates on blocks and / or handles different ssrcs correctly
  122. // generate sources from lines
  123. Object.keys(media.ssrcs).forEach(function(ssrcNum) {
  124. var 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(function (line) {
  129. var idx = line.indexOf(' ');
  130. var kv = line.substr(idx + 1);
  131. modify.c('parameter');
  132. if (kv.indexOf(':') == -1) {
  133. modify.attrs({ name: kv });
  134. } else {
  135. modify.attrs({ name: kv.split(':', 2)[0] });
  136. modify.attrs({ value: kv.split(':', 2)[1] });
  137. }
  138. modify.up(); // end of parameter
  139. });
  140. modify.up(); // end of source
  141. });
  142. // generate source groups from lines
  143. media.ssrcGroups.forEach(function(ssrcGroup) {
  144. if (ssrcGroup.ssrcs.length != 0) {
  145. modify.c('ssrc-group', {
  146. semantics: ssrcGroup.semantics,
  147. xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0'
  148. });
  149. ssrcGroup.ssrcs.forEach(function (ssrc) {
  150. modify.c('source', { ssrc: ssrc })
  151. .up(); // end of source
  152. });
  153. modify.up(); // end of ssrc-group
  154. }
  155. });
  156. modify.up(); // end of description
  157. modify.up(); // end of content
  158. });
  159. return modified;
  160. };
  161. module.exports = SDPDiffer;