Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

SendVideoController.js 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. import { getLogger } from '@jitsi/logger';
  2. import MediaSessionEvents from '../xmpp/MediaSessionEvents';
  3. const logger = getLogger(__filename);
  4. const MAX_LOCAL_RESOLUTION = 2160;
  5. /**
  6. * The class manages send video constraints across media sessions({@link JingleSessionPC}) which belong to
  7. * {@link JitsiConference}. It finds the lowest common value, between the local user's send preference and
  8. * the remote party's receive preference. Also this module will consider only the active session's receive value,
  9. * because local tracks are shared and while JVB may have no preference, the remote p2p may have and they may be totally
  10. * different.
  11. */
  12. export default class SendVideoController {
  13. /**
  14. * Creates new instance for a given conference.
  15. *
  16. * @param {JitsiConference} conference - the conference instance for which the new instance will be managing
  17. * the send video quality constraints.
  18. */
  19. constructor(conference) {
  20. this._conference = conference;
  21. this._preferredSendMaxFrameHeight = MAX_LOCAL_RESOLUTION;
  22. /**
  23. * Source name based sender constraints.
  24. * @type {Map<string, number>};
  25. */
  26. this._sourceSenderConstraints = new Map();
  27. }
  28. /**
  29. * Figures out the send video constraint as specified by {@link _selectSendMaxFrameHeight} and sets it on all media
  30. * sessions for the reasons mentioned in this class description.
  31. *
  32. * @param {string} sourceName - The source for which sender constraints have changed.
  33. * @returns {Promise<void[]>}
  34. * @private
  35. */
  36. _propagateSendMaxFrameHeight(sourceName) {
  37. if (!sourceName) {
  38. throw new Error('sourceName missing for calculating the sendMaxHeight for video tracks');
  39. }
  40. const sendMaxFrameHeight = this._selectSendMaxFrameHeight(sourceName);
  41. const promises = [];
  42. if (sendMaxFrameHeight >= 0) {
  43. for (const session of this._conference.getMediaSessions()) {
  44. promises.push(session.setSenderVideoConstraint(sendMaxFrameHeight, sourceName));
  45. }
  46. }
  47. return Promise.all(promises);
  48. }
  49. /**
  50. * Selects the lowest common value for the local video send constraint by looking at local user's preference and
  51. * the active media session's receive preference set by the remote party.
  52. *
  53. * @param {string} sourceName - The source for which sender constraints have changed.
  54. * @returns {number|undefined}
  55. * @private
  56. */
  57. _selectSendMaxFrameHeight(sourceName) {
  58. if (!sourceName) {
  59. throw new Error('sourceName missing for calculating the sendMaxHeight for video tracks');
  60. }
  61. const activeMediaSession = this._conference.getActiveMediaSession();
  62. const remoteRecvMaxFrameHeight = activeMediaSession
  63. ? this._sourceSenderConstraints.get(sourceName)
  64. : undefined;
  65. if (this._preferredSendMaxFrameHeight >= 0 && remoteRecvMaxFrameHeight >= 0) {
  66. return Math.min(this._preferredSendMaxFrameHeight, remoteRecvMaxFrameHeight);
  67. } else if (remoteRecvMaxFrameHeight >= 0) {
  68. return remoteRecvMaxFrameHeight;
  69. }
  70. return this._preferredSendMaxFrameHeight;
  71. }
  72. /**
  73. * Configures the video encodings on the local sources when a media connection is established or becomes active.
  74. *
  75. * @returns {void}
  76. */
  77. configureConstraintsForLocalSources() {
  78. for (const track of this._conference.getLocalVideoTracks()) {
  79. const sourceName = track.getSourceName();
  80. sourceName && this._propagateSendMaxFrameHeight(sourceName);
  81. }
  82. }
  83. /**
  84. * Handles the {@link JitsiConferenceEvents.MEDIA_SESSION_STARTED}, that is when the conference creates new media
  85. * session. It doesn't mean it's already active though. For example the JVB connection may be created after
  86. * the conference has entered the p2p mode already.
  87. *
  88. * @param {JingleSessionPC} mediaSession - the started media session.
  89. */
  90. onMediaSessionStarted(mediaSession) {
  91. mediaSession.addListener(
  92. MediaSessionEvents.REMOTE_SOURCE_CONSTRAINTS_CHANGED,
  93. (session, sourceConstraints) => {
  94. session === this._conference.getActiveMediaSession()
  95. && sourceConstraints.forEach(constraint => this.onSenderConstraintsReceived(constraint));
  96. });
  97. }
  98. /**
  99. * Propagates the video constraints if they have changed.
  100. *
  101. * @param {Object} videoConstraints - The sender video constraints received from the bridge.
  102. * @returns {Promise<void[]>}
  103. */
  104. onSenderConstraintsReceived(videoConstraints) {
  105. const { maxHeight, sourceName } = videoConstraints;
  106. const localVideoTracks = this._conference.getLocalVideoTracks() ?? [];
  107. for (const track of localVideoTracks) {
  108. // Propagate the sender constraint only if it has changed.
  109. if (track.getSourceName() === sourceName
  110. && this._sourceSenderConstraints.get(sourceName) !== maxHeight) {
  111. this._sourceSenderConstraints.set(
  112. sourceName,
  113. maxHeight === -1
  114. ? Math.min(MAX_LOCAL_RESOLUTION, this._preferredSendMaxFrameHeight)
  115. : maxHeight);
  116. logger.debug(`Sender constraints for source:${sourceName} changed to maxHeight:${maxHeight}`);
  117. this._propagateSendMaxFrameHeight(sourceName);
  118. }
  119. }
  120. }
  121. /**
  122. * Sets local preference for max send video frame height.
  123. *
  124. * @param {number} maxFrameHeight - the new value to set.
  125. * @returns {Promise<void[]>} - resolved when the operation is complete.
  126. */
  127. setPreferredSendMaxFrameHeight(maxFrameHeight) {
  128. this._preferredSendMaxFrameHeight = maxFrameHeight;
  129. const promises = [];
  130. for (const sourceName of this._sourceSenderConstraints.keys()) {
  131. promises.push(this._propagateSendMaxFrameHeight(sourceName));
  132. }
  133. return Promise.allSettled(promises);
  134. }
  135. }