modified lib-jitsi-meet dev repo
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RtxModifier.js 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. import { getLogger } from '@jitsi/logger';
  2. import SDPUtil from './SDPUtil';
  3. import { parseSecondarySSRC, SdpTransformWrap } from './SdpTransformUtil';
  4. const logger = getLogger(__filename);
  5. /**
  6. * Begin helper functions
  7. */
  8. /**
  9. * Updates or inserts the appropriate rtx information for primarySsrc with
  10. * the given rtxSsrc. If no rtx ssrc for primarySsrc currently exists, it will
  11. * add the appropriate ssrc and ssrc group lines. If primarySsrc already has
  12. * an rtx ssrc, the appropriate ssrc and group lines will be updated
  13. * @param {MLineWrap} mLine
  14. * @param {object} primarySsrcInfo the info (ssrc, msid & cname) for the
  15. * primary ssrc
  16. * @param {number} rtxSsrc the rtx ssrc to associate with the primary ssrc
  17. */
  18. function updateAssociatedRtxStream(mLine, primarySsrcInfo, rtxSsrc) {
  19. const primarySsrc = primarySsrcInfo.id;
  20. const primarySsrcMsid = primarySsrcInfo.msid;
  21. const primarySsrcCname = primarySsrcInfo.cname;
  22. const previousRtxSSRC = mLine.getRtxSSRC(primarySsrc);
  23. if (previousRtxSSRC === rtxSsrc) {
  24. return;
  25. }
  26. if (previousRtxSSRC) {
  27. // Stream already had an rtx ssrc that is different than the one given,
  28. // remove all trace of the old one
  29. mLine.removeSSRC(previousRtxSSRC);
  30. mLine.removeGroupsWithSSRC(previousRtxSSRC);
  31. }
  32. mLine.addSSRCAttribute({
  33. id: rtxSsrc,
  34. attribute: 'cname',
  35. value: primarySsrcCname
  36. });
  37. mLine.addSSRCAttribute({
  38. id: rtxSsrc,
  39. attribute: 'msid',
  40. value: primarySsrcMsid
  41. });
  42. mLine.addSSRCGroup({
  43. semantics: 'FID',
  44. ssrcs: `${primarySsrc} ${rtxSsrc}`
  45. });
  46. }
  47. /**
  48. * End helper functions
  49. */
  50. /**
  51. * Adds any missing RTX streams for video streams
  52. * and makes sure that they remain consistent
  53. */
  54. export default class RtxModifier {
  55. /**
  56. * Constructor
  57. */
  58. constructor() {
  59. /**
  60. * Map of video ssrc to corresponding RTX
  61. * ssrc
  62. */
  63. this.correspondingRtxSsrcs = new Map();
  64. }
  65. /**
  66. * Clear the cached map of primary video ssrcs to
  67. * their corresponding rtx ssrcs so that they will
  68. * not be used for the next call to modifyRtxSsrcs
  69. */
  70. clearSsrcCache() {
  71. this.correspondingRtxSsrcs.clear();
  72. }
  73. /**
  74. * Explicitly set the primary video ssrc -> rtx ssrc
  75. * mapping to be used in modifyRtxSsrcs
  76. * @param {Map} ssrcMapping a mapping of primary video
  77. * ssrcs to their corresponding rtx ssrcs
  78. */
  79. setSsrcCache(ssrcMapping) {
  80. logger.debug('Setting ssrc cache to ', ssrcMapping);
  81. this.correspondingRtxSsrcs = ssrcMapping;
  82. }
  83. /**
  84. * Adds RTX ssrcs for any video ssrcs that don't
  85. * already have them. If the video ssrc has been
  86. * seen before, and already had an RTX ssrc generated,
  87. * the same RTX ssrc will be used again.
  88. * @param {string} sdpStr sdp in raw string format
  89. */
  90. modifyRtxSsrcs(sdpStr) {
  91. const sdpTransformer = new SdpTransformWrap(sdpStr);
  92. const videoMLine = sdpTransformer.selectMedia('video');
  93. if (!videoMLine) {
  94. logger.debug(`No 'video' media found in the sdp: ${sdpStr}`);
  95. return sdpStr;
  96. }
  97. return this.modifyRtxSsrcs2(videoMLine)
  98. ? sdpTransformer.toRawSDP() : sdpStr;
  99. }
  100. /**
  101. * Does the same thing as {@link modifyRtxSsrcs}, but takes the
  102. * {@link MLineWrap} instance wrapping video media as an argument.
  103. * @param {MLineWrap} videoMLine
  104. * @return {boolean} <tt>true</tt> if the SDP wrapped by
  105. * {@link SdpTransformWrap} has been modified or <tt>false</tt> otherwise.
  106. */
  107. modifyRtxSsrcs2(videoMLine) {
  108. if (videoMLine.direction === 'recvonly') {
  109. return false;
  110. }
  111. if (videoMLine.getSSRCCount() < 1) {
  112. return false;
  113. }
  114. const primaryVideoSsrcs = videoMLine.getPrimaryVideoSSRCs();
  115. for (const ssrc of primaryVideoSsrcs) {
  116. const msid = videoMLine.getSSRCAttrValue(ssrc, 'msid');
  117. const cname = videoMLine.getSSRCAttrValue(ssrc, 'cname');
  118. let correspondingRtxSsrc = this.correspondingRtxSsrcs.get(ssrc);
  119. if (!correspondingRtxSsrc) {
  120. // If there's one in the sdp already for it, we'll just set
  121. // that as the corresponding one
  122. const previousAssociatedRtxStream = videoMLine.getRtxSSRC(ssrc);
  123. if (previousAssociatedRtxStream) {
  124. correspondingRtxSsrc = previousAssociatedRtxStream;
  125. } else {
  126. correspondingRtxSsrc = SDPUtil.generateSsrc();
  127. }
  128. this.correspondingRtxSsrcs.set(ssrc, correspondingRtxSsrc);
  129. }
  130. updateAssociatedRtxStream(
  131. videoMLine,
  132. {
  133. id: ssrc,
  134. cname,
  135. msid
  136. },
  137. correspondingRtxSsrc);
  138. }
  139. // FIXME we're not looking into much details whether the SDP has been
  140. // modified or not once the precondition requirements are met.
  141. return true;
  142. }
  143. /**
  144. * Strip all rtx streams from the given sdp
  145. * @param {string} sdpStr sdp in raw string format
  146. * @returns {string} sdp string with all rtx streams stripped
  147. */
  148. stripRtx(sdpStr) {
  149. const sdpTransformer = new SdpTransformWrap(sdpStr);
  150. const videoMLine = sdpTransformer.selectMedia('video');
  151. if (!videoMLine) {
  152. logger.debug(`No 'video' media found in the sdp: ${sdpStr}`);
  153. return sdpStr;
  154. }
  155. if (videoMLine.direction === 'recvonly') {
  156. logger.debug('RtxModifier doing nothing, video m line is recvonly');
  157. return sdpStr;
  158. }
  159. if (videoMLine.getSSRCCount() < 1) {
  160. logger.debug('RtxModifier doing nothing, no video ssrcs present');
  161. return sdpStr;
  162. }
  163. if (!videoMLine.containsAnySSRCGroups()) {
  164. logger.debug('RtxModifier doing nothing, '
  165. + 'no video ssrcGroups present');
  166. return sdpStr;
  167. }
  168. const fidGroups = videoMLine.findGroups('FID');
  169. // Remove the fid groups from the mline
  170. videoMLine.removeGroupsBySemantics('FID');
  171. // Get the rtx ssrcs and remove them from the mline
  172. for (const fidGroup of fidGroups) {
  173. const rtxSsrc = parseSecondarySSRC(fidGroup);
  174. videoMLine.removeSSRC(rtxSsrc);
  175. }
  176. return sdpTransformer.toRawSDP();
  177. }
  178. }