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.

SdpConsistency.js 4.3KB

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