Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

SdpConsistency.js 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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. */
  20. constructor() {
  21. this.clearVideoSsrcCache();
  22. /**
  23. * Cached audio SSRC.
  24. * @type {number|null}
  25. */
  26. this.cachedAudioSSRC = null;
  27. }
  28. /**
  29. * Clear the cached video primary and primary rtx ssrcs so that
  30. * they will not be used for the next call to
  31. * makeVideoPrimarySsrcsConsistent
  32. */
  33. clearVideoSsrcCache() {
  34. this.cachedPrimarySsrc = null;
  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. * Given an sdp string, either:
  51. * 1) record the primary video and primary rtx ssrcs to be
  52. * used in future calls to makeVideoPrimarySsrcsConsistent or
  53. * 2) change the primary and primary rtx ssrcs in the given sdp
  54. * to match the ones previously cached
  55. * @param {string} sdpStr the sdp string to (potentially)
  56. * change to make the video ssrcs consistent
  57. * @returns {string} a (potentially) modified sdp string
  58. * with ssrcs consistent with this class' cache
  59. */
  60. makeVideoPrimarySsrcsConsistent(sdpStr) {
  61. const sdpTransformer = new SdpTransformWrap(sdpStr);
  62. const videoMLine = sdpTransformer.selectMedia('video');
  63. if (!videoMLine) {
  64. logger.error(`No 'video' media found in the sdp: ${sdpStr}`);
  65. return sdpStr;
  66. }
  67. if (videoMLine.direction === 'inactive') {
  68. logger.info(
  69. 'Sdp-consistency doing nothing, video mline is inactive');
  70. return sdpStr;
  71. }
  72. if (videoMLine.direction === 'recvonly') {
  73. // If the mline is recvonly, we'll add the primary
  74. // ssrc as a recvonly ssrc
  75. if (this.cachedPrimarySsrc) {
  76. videoMLine.addSSRCAttribute({
  77. id: this.cachedPrimarySsrc,
  78. attribute: 'cname',
  79. value: `recvonly-${this.cachedPrimarySsrc}`
  80. });
  81. } else {
  82. logger.error('No SSRC found for the recvonly video stream!');
  83. }
  84. } else {
  85. const newPrimarySsrc = videoMLine.getPrimaryVideoSsrc();
  86. if (!newPrimarySsrc) {
  87. logger.info('Sdp-consistency couldn\'t parse new primary ssrc');
  88. return sdpStr;
  89. }
  90. if (this.cachedPrimarySsrc) {
  91. logger.info(
  92. `Sdp-consistency replacing new ssrc ${newPrimarySsrc
  93. } with cached ${this.cachedPrimarySsrc}`);
  94. videoMLine.replaceSSRC(newPrimarySsrc, this.cachedPrimarySsrc);
  95. for (const group of videoMLine.ssrcGroups) {
  96. if (group.semantics === 'FID') {
  97. const primarySsrc = parsePrimarySSRC(group);
  98. const rtxSsrc = parseSecondarySSRC(group);
  99. // eslint-disable-next-line max-depth
  100. if (primarySsrc === newPrimarySsrc) {
  101. group.ssrcs
  102. = `${this.cachedPrimarySsrc} ${rtxSsrc}`;
  103. }
  104. }
  105. }
  106. } else {
  107. this.cachedPrimarySsrc = newPrimarySsrc;
  108. logger.info(
  109. `Sdp-consistency caching primary ssrc ${
  110. this.cachedPrimarySsrc}`);
  111. }
  112. }
  113. return sdpTransformer.toRawSDP();
  114. }
  115. /**
  116. * Makes sure that audio SSRC is preserved between "detach" and "attach"
  117. * operations. The code assumes there can be only 1 audio track added to
  118. * the peer connection at a time.
  119. * @param {string} sdpStr the sdp string to (potentially)
  120. * change to make the audio ssrc consistent
  121. * @returns {string} a (potentially) modified sdp string
  122. * with ssrcs consistent with this class' cache
  123. */
  124. makeAudioSSRCConsistent(sdpStr) {
  125. const sdpTransformer = new SdpTransformWrap(sdpStr);
  126. const audioMLine = sdpTransformer.selectMedia('audio');
  127. if (!audioMLine) {
  128. logger.error(`No 'audio' media found in the sdp: ${sdpStr}`);
  129. return sdpStr;
  130. }
  131. if (audioMLine.direction === 'inactive') {
  132. logger.info(
  133. 'Sdp-consistency doing nothing, audio mline is inactive');
  134. return sdpStr;
  135. }
  136. const audioSSRCObj = audioMLine.findSSRCByMSID(null);
  137. if (audioSSRCObj) {
  138. if (this.cachedAudioSSRC) {
  139. const oldSSRC = audioSSRCObj.id;
  140. if (oldSSRC !== this.cachedAudioSSRC) {
  141. logger.info(
  142. `Replacing audio SSRC ${
  143. oldSSRC} with ${this.cachedAudioSSRC}`);
  144. audioMLine.replaceSSRC(oldSSRC, this.cachedAudioSSRC);
  145. }
  146. } else {
  147. this.cachedAudioSSRC = audioSSRCObj.id;
  148. logger.info(`Storing audio SSRC: ${this.cachedAudioSSRC}`);
  149. }
  150. } else {
  151. logger.info('Doing nothing - no audio stream in the SDP');
  152. }
  153. return sdpTransformer.toRawSDP();
  154. }
  155. }