modified lib-jitsi-meet dev repo
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

ReceiveVideoController.js 9.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. import { getLogger } from 'jitsi-meet-logger';
  2. import * as JitsiConferenceEvents from '../../JitsiConferenceEvents';
  3. const logger = getLogger(__filename);
  4. const MAX_HEIGHT_ONSTAGE = 2160;
  5. const MAX_HEIGHT_THUMBNAIL = 180;
  6. const LASTN_UNLIMITED = -1;
  7. /**
  8. * This class translates the legacy signaling format between the client and the bridge (that affects bandwidth
  9. * allocation) to the new format described here https://github.com/jitsi/jitsi-videobridge/blob/master/doc/allocation.md
  10. */
  11. export class ReceiverVideoConstraints {
  12. /**
  13. * Creates a new instance.
  14. */
  15. constructor() {
  16. // Default constraints used for endpoints that are not explicitly included in constraints.
  17. // These constraints are used for endpoints that are thumbnails in the stage view.
  18. this._defaultConstraints = { 'maxHeight': MAX_HEIGHT_THUMBNAIL };
  19. // The number of videos requested from the bridge.
  20. this._lastN = LASTN_UNLIMITED;
  21. // The number representing the maximum video height the local client should receive from the bridge.
  22. this._maxFrameHeight = MAX_HEIGHT_ONSTAGE;
  23. // The endpoint IDs of the participants that are currently selected.
  24. this._selectedEndpoints = [];
  25. this._receiverVideoConstraints = {
  26. constraints: {},
  27. defaultConstraints: this.defaultConstraints,
  28. lastN: this._lastN,
  29. onStageEndpoints: [],
  30. selectedEndpoints: this._selectedEndpoints
  31. };
  32. }
  33. /**
  34. * Returns the receiver video constraints that need to be sent on the bridge channel.
  35. */
  36. get constraints() {
  37. this._receiverVideoConstraints.lastN = this._lastN;
  38. if (!this._selectedEndpoints.length) {
  39. return this._receiverVideoConstraints;
  40. }
  41. // The client is assumed to be in TileView if it has selected more than one endpoint, otherwise it is
  42. // assumed to be in StageView.
  43. this._receiverVideoConstraints.constraints = {};
  44. if (this._selectedEndpoints.length > 1) {
  45. /**
  46. * Tile view.
  47. * Only the default constraints are specified here along with lastN (if it is set).
  48. * {
  49. * 'colibriClass': 'ReceiverVideoConstraints',
  50. * 'defaultConstraints': { 'maxHeight': 360 }
  51. * }
  52. */
  53. this._receiverVideoConstraints.defaultConstraints = { 'maxHeight': this._maxFrameHeight };
  54. this._receiverVideoConstraints.onStageEndpoints = [];
  55. this._receiverVideoConstraints.selectedEndpoints = [];
  56. } else {
  57. /**
  58. * Stage view.
  59. * The participant on stage is specified in onStageEndpoints and a higher maxHeight is specified
  60. * for that endpoint while a default maxHeight of 180 is applied to all the other endpoints.
  61. * {
  62. * 'colibriClass': 'ReceiverVideoConstraints',
  63. * 'onStageEndpoints': ['A'],
  64. * 'defaultConstraints': { 'maxHeight': 180 },
  65. * 'constraints': {
  66. * 'A': { 'maxHeight': 720 }
  67. * }
  68. * }
  69. */
  70. this._receiverVideoConstraints.constraints[this._selectedEndpoints[0]] = {
  71. 'maxHeight': this._maxFrameHeight
  72. };
  73. this._receiverVideoConstraints.defaultConstraints = this._defaultConstraints;
  74. this._receiverVideoConstraints.onStageEndpoints = this._selectedEndpoints;
  75. this._receiverVideoConstraints.selectedEndpoints = [];
  76. }
  77. return this._receiverVideoConstraints;
  78. }
  79. /**
  80. * Updates the lastN field of the ReceiverVideoConstraints sent to the bridge.
  81. *
  82. * @param {number} value
  83. * @returns {boolean} Returns true if the the value has been updated, false otherwise.
  84. */
  85. updateLastN(value) {
  86. const changed = this._lastN !== value;
  87. if (changed) {
  88. this._lastN = value;
  89. logger.debug(`Updating ReceiverVideoConstraints lastN(${value})`);
  90. }
  91. return changed;
  92. }
  93. /**
  94. * Updates the resolution (height requested) in the contraints field of the ReceiverVideoConstraints
  95. * sent to the bridge.
  96. *
  97. * @param {number} maxFrameHeight
  98. * @requires {boolean} Returns true if the the value has been updated, false otherwise.
  99. */
  100. updateReceiveResolution(maxFrameHeight) {
  101. const changed = this._maxFrameHeight !== maxFrameHeight;
  102. if (changed) {
  103. this._maxFrameHeight = maxFrameHeight;
  104. logger.debug(`Updating receive maxFrameHeight: ${maxFrameHeight}`);
  105. }
  106. return changed;
  107. }
  108. /**
  109. * Updates the list of selected endpoints.
  110. *
  111. * @param {Array<string>} ids
  112. * @returns {void}
  113. */
  114. updateSelectedEndpoints(ids) {
  115. logger.debug(`Updating selected endpoints: ${JSON.stringify(ids)}`);
  116. this._selectedEndpoints = ids;
  117. }
  118. }
  119. /**
  120. * This class manages the receive video contraints for a given {@link JitsiConference}. These constraints are
  121. * determined by the application based on how the remote video streams need to be displayed. This class is responsible
  122. * for communicating these constraints to the bridge over the bridge channel.
  123. */
  124. export class ReceiveVideoController {
  125. /**
  126. * Creates a new instance for a given conference.
  127. *
  128. * @param {JitsiConference} conference the conference instance for which the new instance will be managing
  129. * the receive video quality constraints.
  130. * @param {RTC} rtc the rtc instance which is responsible for initializing the bridge channel.
  131. */
  132. constructor(conference, rtc) {
  133. this._conference = conference;
  134. this._rtc = rtc;
  135. // Translate the legacy bridge channel signaling format to the new format.
  136. this._receiverVideoConstraints = conference.options?.config?.useNewBandwidthAllocationStrategy
  137. ? new ReceiverVideoConstraints()
  138. : undefined;
  139. // The number of videos requested from the bridge, -1 represents unlimited or all available videos.
  140. this._lastN = LASTN_UNLIMITED;
  141. // The number representing the maximum video height the local client should receive from the bridge.
  142. this._maxFrameHeight = MAX_HEIGHT_ONSTAGE;
  143. // The endpoint IDs of the participants that are currently selected.
  144. this._selectedEndpoints = [];
  145. this._conference.on(
  146. JitsiConferenceEvents._MEDIA_SESSION_STARTED,
  147. session => this._onMediaSessionStarted(session));
  148. }
  149. /**
  150. * Handles the {@link JitsiConferenceEvents.MEDIA_SESSION_STARTED}, that is when the conference creates new media
  151. * session. The preferred receive frameHeight is applied on the media session.
  152. *
  153. * @param {JingleSessionPC} mediaSession - the started media session.
  154. * @returns {void}
  155. * @private
  156. */
  157. _onMediaSessionStarted(mediaSession) {
  158. this._maxFrameHeight && mediaSession.setReceiverVideoConstraint(this._maxFrameHeight);
  159. }
  160. /**
  161. * Elects the participants with the given ids to be the selected participants in order to always receive video
  162. * for this participant (even when last n is enabled).
  163. *
  164. * @param {Array<string>} ids - The user ids.
  165. * @returns {void}
  166. */
  167. selectEndpoints(ids) {
  168. this._selectedEndpoints = ids;
  169. if (this._receiverVideoConstraints) {
  170. const remoteEndpointIds = ids.filter(id => id !== this._conference.myUserId());
  171. // Filter out the local endpointId from the list of selected endpoints.
  172. remoteEndpointIds.length && this._receiverVideoConstraints.updateSelectedEndpoints(remoteEndpointIds);
  173. this._rtc.setNewReceiverVideoConstraints(this._receiverVideoConstraints.constraints);
  174. return;
  175. }
  176. this._rtc.selectEndpoints(ids);
  177. }
  178. /**
  179. * Selects a new value for "lastN". The requested amount of videos are going to be delivered after the value is
  180. * in effect. Set to -1 for unlimited or all available videos.
  181. *
  182. * @param {number} value the new value for lastN.
  183. * @returns {void}
  184. */
  185. setLastN(value) {
  186. if (this._lastN !== value) {
  187. this._lastN = value;
  188. if (this._receiverVideoConstraints) {
  189. const lastNUpdated = this._receiverVideoConstraints.updateLastN(value);
  190. // Send out the message on the bridge channel if lastN was updated.
  191. lastNUpdated && this._rtc.setNewReceiverVideoConstraints(this._receiverVideoConstraints.constraints);
  192. return;
  193. }
  194. this._rtc.setLastN(value);
  195. }
  196. }
  197. /**
  198. * Sets the maximum video resolution the local participant should receive from remote participants.
  199. *
  200. * @param {number|undefined} maxFrameHeight - the new value.
  201. * @returns {void}
  202. */
  203. setPreferredReceiveMaxFrameHeight(maxFrameHeight) {
  204. this._maxFrameHeight = maxFrameHeight;
  205. for (const session of this._conference._getMediaSessions()) {
  206. if (session.isP2P || !this._receiverVideoConstraints) {
  207. maxFrameHeight && session.setReceiverVideoConstraint(maxFrameHeight);
  208. } else {
  209. const resolutionUpdated = this._receiverVideoConstraints.updateReceiveResolution(maxFrameHeight);
  210. resolutionUpdated
  211. && this._rtc.setNewReceiverVideoConstraints(this._receiverVideoConstraints.constraints);
  212. }
  213. }
  214. }
  215. }