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

SpeakerStatsCollector.js 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. import * as JitsiConferenceEvents from '../../JitsiConferenceEvents';
  2. import { XMPPEvents } from '../../service/xmpp/XMPPEvents';
  3. import SpeakerStats from './SpeakerStats';
  4. /**
  5. * A collection for tracking speaker stats. Attaches listeners
  6. * to the conference to automatically update on tracked events.
  7. */
  8. export default class SpeakerStatsCollector {
  9. /**
  10. * Initializes a new SpeakerStatsCollector instance.
  11. *
  12. * @constructor
  13. * @param {JitsiConference} conference - The conference to track.
  14. * @returns {void}
  15. */
  16. constructor(conference) {
  17. this.stats = {
  18. users: {
  19. // userId: SpeakerStats
  20. },
  21. dominantSpeakerId: null
  22. };
  23. const userId = conference.myUserId();
  24. this.stats.users[userId] = new SpeakerStats(userId, null, true);
  25. this.conference = conference;
  26. conference.addEventListener(
  27. JitsiConferenceEvents.DOMINANT_SPEAKER_CHANGED,
  28. this._onDominantSpeaker.bind(this));
  29. conference.addEventListener(
  30. JitsiConferenceEvents.USER_JOINED,
  31. this._onUserJoin.bind(this));
  32. conference.addEventListener(
  33. JitsiConferenceEvents.USER_LEFT,
  34. this._onUserLeave.bind(this));
  35. conference.addEventListener(
  36. JitsiConferenceEvents.DISPLAY_NAME_CHANGED,
  37. this._onDisplayNameChange.bind(this));
  38. conference.addEventListener(
  39. JitsiConferenceEvents.FACE_LANDMARK_ADDED,
  40. this._onFaceLandmarkAdd.bind(this));
  41. if (conference.xmpp) {
  42. conference.xmpp.addListener(
  43. XMPPEvents.SPEAKER_STATS_RECEIVED,
  44. this._updateStats.bind(this));
  45. }
  46. }
  47. /**
  48. * Reacts to dominant speaker change events by changing its speaker stats
  49. * models to reflect the current dominant speaker.
  50. *
  51. * @param {string} dominantSpeakerId - The user id of the new dominant speaker.
  52. * @param {Array[string]} previous - The array with previous speakers.
  53. * @param {boolean} silence - Indecates whether the dominant speaker is silent or not.
  54. * @returns {void}
  55. * @private
  56. */
  57. _onDominantSpeaker(dominantSpeakerId, previous, silence) {
  58. const oldDominantSpeaker
  59. = this.stats.users[this.stats.dominantSpeakerId];
  60. const newDominantSpeaker = this.stats.users[dominantSpeakerId];
  61. oldDominantSpeaker && oldDominantSpeaker.setDominantSpeaker(false);
  62. newDominantSpeaker && newDominantSpeaker.setDominantSpeaker(true, silence);
  63. this.stats.dominantSpeakerId = dominantSpeakerId;
  64. }
  65. /**
  66. * Reacts to user join events by creating a new SpeakerStats model.
  67. *
  68. * @param {string} userId - The user id of the new user.
  69. * @param {JitsiParticipant} - The JitsiParticipant model for the new user.
  70. * @returns {void}
  71. * @private
  72. */
  73. _onUserJoin(userId, participant) {
  74. if (participant.isHidden()) {
  75. return;
  76. }
  77. if (!this.stats.users[userId]) {
  78. this.stats.users[userId] = new SpeakerStats(userId, participant.getDisplayName());
  79. }
  80. }
  81. /**
  82. * Reacts to user leave events by updating the associated user's
  83. * SpeakerStats model.
  84. *
  85. * @param {string} userId - The user id of the user that left.
  86. * @returns {void}
  87. * @private
  88. */
  89. _onUserLeave(userId) {
  90. const savedUser = this.stats.users[userId];
  91. if (savedUser) {
  92. savedUser.markAsHasLeft();
  93. }
  94. }
  95. /**
  96. * Reacts to user name change events by updating the last known name
  97. * tracked in the associated SpeakerStats model.
  98. *
  99. * @param {string} userId - The user id of the user that left.
  100. * @returns {void}
  101. * @private
  102. */
  103. _onDisplayNameChange(userId, newName) {
  104. const savedUser = this.stats.users[userId];
  105. if (savedUser) {
  106. savedUser.setDisplayName(newName);
  107. }
  108. }
  109. /**
  110. * Processes a new face landmark object of a remote user.
  111. *
  112. * @param {string} userId - The user id of the user that left.
  113. * @param {Object} data - The face landmark object.
  114. * @returns {void}
  115. * @private
  116. */
  117. _onFaceLandmarkAdd(userId, data) {
  118. const savedUser = this.stats.users[userId];
  119. if (savedUser && data.faceExpression) {
  120. savedUser.addFaceExpression(data.faceExpression, data.duration);
  121. }
  122. }
  123. /**
  124. * Return a copy of the tracked SpeakerStats models.
  125. *
  126. * @returns {Object} The keys are the user ids and the values are the
  127. * associated user's SpeakerStats model.
  128. */
  129. getStats() {
  130. return this.stats.users;
  131. }
  132. /**
  133. * Updates of the current stats is requested, passing the new values.
  134. *
  135. * @param {Object} newStats - The new values used to update current one.
  136. * @private
  137. */
  138. _updateStats(newStats) {
  139. for (const userId in newStats) { // eslint-disable-line guard-for-in
  140. let speakerStatsToUpdate;
  141. const newParticipant = this.conference.getParticipantById(userId);
  142. // we want to ignore hidden participants
  143. if (!newParticipant || !newParticipant.isHidden()) {
  144. if (this.stats.users[userId]) {
  145. speakerStatsToUpdate = this.stats.users[userId];
  146. if (!speakerStatsToUpdate.getDisplayName()) {
  147. speakerStatsToUpdate
  148. .setDisplayName(newStats[userId].displayName);
  149. }
  150. } else {
  151. speakerStatsToUpdate = new SpeakerStats(
  152. userId, newStats[userId].displayName);
  153. this.stats.users[userId] = speakerStatsToUpdate;
  154. speakerStatsToUpdate.markAsHasLeft();
  155. }
  156. }
  157. speakerStatsToUpdate.totalDominantSpeakerTime
  158. = newStats[userId].totalDominantSpeakerTime;
  159. speakerStatsToUpdate.setFaceExpressions(newStats[userId].faceExpressions);
  160. }
  161. }
  162. }