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

SdpConsistency.js 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. /* global __filename */
  2. import { getLogger } from 'jitsi-meet-logger';
  3. import {
  4. parsePrimarySSRC,
  5. parseSecondarySSRC,
  6. SdpTransformWrap
  7. } from './SdpTransformUtil';
  8. const logger = getLogger(__filename);
  9. /**
  10. * Handles the work of keeping video ssrcs consistent across multiple
  11. * o/a cycles, making it such that all stream operations can be
  12. * kept local and do not need to be signaled.
  13. * NOTE: This only keeps the 'primary' video ssrc consistent: meaning
  14. * the primary video stream
  15. */
  16. export default class SdpConsistency {
  17. /**
  18. * Constructor
  19. * @param {string} logPrefix the log prefix appended to every logged
  20. * message, currently used to distinguish for which
  21. * <tt>TraceablePeerConnection</tt> the instance works.
  22. */
  23. constructor(logPrefix) {
  24. this.clearVideoSsrcCache();
  25. this.logPrefix = logPrefix;
  26. }
  27. /**
  28. * Clear the cached video primary and primary rtx ssrcs so that
  29. * they will not be used for the next call to
  30. * makeVideoPrimarySsrcsConsistent
  31. */
  32. clearVideoSsrcCache() {
  33. this.cachedPrimarySsrc = null;
  34. this.injectRecvOnly = false;
  35. }
  36. /**
  37. * Explicitly set the primary ssrc to be used in
  38. * makeVideoPrimarySsrcsConsistent
  39. * @param {number} primarySsrc the primarySsrc to be used
  40. * in future calls to makeVideoPrimarySsrcsConsistent
  41. * @throws Error if <tt>primarySsrc</tt> is not a number
  42. */
  43. setPrimarySsrc(primarySsrc) {
  44. if (typeof primarySsrc !== 'number') {
  45. throw new Error('Primary SSRC must be a number!');
  46. }
  47. this.cachedPrimarySsrc = primarySsrc;
  48. }
  49. /**
  50. * Checks whether or not there is a primary video SSRC cached already.
  51. * @return {boolean}
  52. */
  53. hasPrimarySsrcCached() {
  54. return Boolean(this.cachedPrimarySsrc);
  55. }
  56. /**
  57. * Given an sdp string, either:
  58. * 1) record the primary video and primary rtx ssrcs to be
  59. * used in future calls to makeVideoPrimarySsrcsConsistent or
  60. * 2) change the primary and primary rtx ssrcs in the given sdp
  61. * to match the ones previously cached
  62. * @param {string} sdpStr the sdp string to (potentially)
  63. * change to make the video ssrcs consistent
  64. * @returns {string} a (potentially) modified sdp string
  65. * with ssrcs consistent with this class' cache
  66. */
  67. makeVideoPrimarySsrcsConsistent(sdpStr) {
  68. const sdpTransformer = new SdpTransformWrap(sdpStr);
  69. const videoMLine = sdpTransformer.selectMedia('video');
  70. if (!videoMLine) {
  71. logger.debug(
  72. `${this.logPrefix} no 'video' media found in the sdp: `
  73. + `${sdpStr}`);
  74. return sdpStr;
  75. }
  76. if (videoMLine.direction === 'recvonly') {
  77. // If the mline is recvonly, we'll add the primary
  78. // ssrc as a recvonly ssrc
  79. if (this.cachedPrimarySsrc && this.injectRecvOnly) {
  80. videoMLine.addSSRCAttribute({
  81. id: this.cachedPrimarySsrc,
  82. attribute: 'cname',
  83. value: `recvonly-${this.cachedPrimarySsrc}`
  84. });
  85. } else {
  86. logger.info(
  87. `${this.logPrefix} no SSRC found for the recvonly video`
  88. + 'stream!');
  89. }
  90. } else {
  91. const newPrimarySsrc = videoMLine.getPrimaryVideoSsrc();
  92. if (!newPrimarySsrc) {
  93. logger.info(
  94. `${this.logPrefix} sdp-consistency couldn't`
  95. + ' parse new primary ssrc');
  96. return sdpStr;
  97. }
  98. if (this.cachedPrimarySsrc) {
  99. logger.info(
  100. `${this.logPrefix} sdp-consistency replacing new ssrc`
  101. + `${newPrimarySsrc} with cached `
  102. + `${this.cachedPrimarySsrc}`);
  103. videoMLine.replaceSSRC(newPrimarySsrc, this.cachedPrimarySsrc);
  104. for (const group of videoMLine.ssrcGroups) {
  105. if (group.semantics === 'FID') {
  106. const primarySsrc = parsePrimarySSRC(group);
  107. const rtxSsrc = parseSecondarySSRC(group);
  108. // eslint-disable-next-line max-depth
  109. if (primarySsrc === newPrimarySsrc) {
  110. group.ssrcs
  111. = `${this.cachedPrimarySsrc} ${rtxSsrc}`;
  112. }
  113. }
  114. }
  115. } else {
  116. this.cachedPrimarySsrc = newPrimarySsrc;
  117. logger.info(
  118. `${this.logPrefix} sdp-consistency caching primary ssrc`
  119. + `${this.cachedPrimarySsrc}`);
  120. }
  121. this.injectRecvOnly = true;
  122. }
  123. return sdpTransformer.toRawSDP();
  124. }
  125. }