Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

ReceiveVideoController.js 9.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  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. * Returns the lastN value for the conference.
  162. *
  163. * @returns {number}
  164. */
  165. getLastN() {
  166. return this._lastN;
  167. }
  168. /**
  169. * Elects the participants with the given ids to be the selected participants in order to always receive video
  170. * for this participant (even when last n is enabled).
  171. *
  172. * @param {Array<string>} ids - The user ids.
  173. * @returns {void}
  174. */
  175. selectEndpoints(ids) {
  176. this._selectedEndpoints = ids;
  177. if (this._receiverVideoConstraints) {
  178. const remoteEndpointIds = ids.filter(id => id !== this._conference.myUserId());
  179. // Filter out the local endpointId from the list of selected endpoints.
  180. remoteEndpointIds.length && this._receiverVideoConstraints.updateSelectedEndpoints(remoteEndpointIds);
  181. this._rtc.setNewReceiverVideoConstraints(this._receiverVideoConstraints.constraints);
  182. return;
  183. }
  184. this._rtc.selectEndpoints(ids);
  185. }
  186. /**
  187. * Selects a new value for "lastN". The requested amount of videos are going to be delivered after the value is
  188. * in effect. Set to -1 for unlimited or all available videos.
  189. *
  190. * @param {number} value the new value for lastN.
  191. * @returns {void}
  192. */
  193. setLastN(value) {
  194. if (this._lastN !== value) {
  195. this._lastN = value;
  196. if (this._receiverVideoConstraints) {
  197. const lastNUpdated = this._receiverVideoConstraints.updateLastN(value);
  198. // Send out the message on the bridge channel if lastN was updated.
  199. lastNUpdated && this._rtc.setNewReceiverVideoConstraints(this._receiverVideoConstraints.constraints);
  200. return;
  201. }
  202. this._rtc.setLastN(value);
  203. }
  204. }
  205. /**
  206. * Sets the maximum video resolution the local participant should receive from remote participants.
  207. *
  208. * @param {number|undefined} maxFrameHeight - the new value.
  209. * @returns {void}
  210. */
  211. setPreferredReceiveMaxFrameHeight(maxFrameHeight) {
  212. this._maxFrameHeight = maxFrameHeight;
  213. for (const session of this._conference._getMediaSessions()) {
  214. if (session.isP2P || !this._receiverVideoConstraints) {
  215. maxFrameHeight && session.setReceiverVideoConstraint(maxFrameHeight);
  216. } else {
  217. const resolutionUpdated = this._receiverVideoConstraints.updateReceiveResolution(maxFrameHeight);
  218. resolutionUpdated
  219. && this._rtc.setNewReceiverVideoConstraints(this._receiverVideoConstraints.constraints);
  220. }
  221. }
  222. }
  223. }