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

RtxModifier.js 6.6KB

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