modified lib-jitsi-meet dev repo
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SpeakerStatsCollector.js 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  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.FACIAL_EXPRESSION_ADDED,
  40. this._onFacialExpressionAdd.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
  52. * dominant speaker.
  53. * @returns {void}
  54. * @private
  55. */
  56. _onDominantSpeaker(dominantSpeakerId) {
  57. const oldDominantSpeaker
  58. = this.stats.users[this.stats.dominantSpeakerId];
  59. const newDominantSpeaker = this.stats.users[dominantSpeakerId];
  60. oldDominantSpeaker && oldDominantSpeaker.setDominantSpeaker(false);
  61. newDominantSpeaker && newDominantSpeaker.setDominantSpeaker(true);
  62. this.stats.dominantSpeakerId = dominantSpeakerId;
  63. }
  64. /**
  65. * Reacts to user join events by creating a new SpeakerStats model.
  66. *
  67. * @param {string} userId - The user id of the new user.
  68. * @param {JitsiParticipant} - The JitsiParticipant model for the new user.
  69. * @returns {void}
  70. * @private
  71. */
  72. _onUserJoin(userId, participant) {
  73. if (participant.isHidden()) {
  74. return;
  75. }
  76. if (!this.stats.users[userId]) {
  77. this.stats.users[userId] = new SpeakerStats(userId, participant.getDisplayName());
  78. }
  79. }
  80. /**
  81. * Reacts to user leave events by updating the associated user's
  82. * SpeakerStats model.
  83. *
  84. * @param {string} userId - The user id of the user that left.
  85. * @returns {void}
  86. * @private
  87. */
  88. _onUserLeave(userId) {
  89. const savedUser = this.stats.users[userId];
  90. if (savedUser) {
  91. savedUser.markAsHasLeft();
  92. }
  93. }
  94. /**
  95. * Reacts to user name change events by updating the last known name
  96. * tracked in the associated SpeakerStats model.
  97. *
  98. * @param {string} userId - The user id of the user that left.
  99. * @returns {void}
  100. * @private
  101. */
  102. _onDisplayNameChange(userId, newName) {
  103. const savedUser = this.stats.users[userId];
  104. if (savedUser) {
  105. savedUser.setDisplayName(newName);
  106. }
  107. }
  108. /**
  109. * Adds a new facial expression with its duration of a remote user.
  110. *
  111. * @param {string} userId - The user id of the user that left.
  112. * @param {Object} data - The facial expression with its duration.
  113. * @returns {void}
  114. * @private
  115. */
  116. _onFacialExpressionAdd(userId, data) {
  117. const savedUser = this.stats.users[userId];
  118. if (savedUser) {
  119. savedUser.addFacialExpression(data.facialExpression, data.duration);
  120. }
  121. }
  122. /**
  123. * Return a copy of the tracked SpeakerStats models.
  124. *
  125. * @returns {Object} The keys are the user ids and the values are the
  126. * associated user's SpeakerStats model.
  127. */
  128. getStats() {
  129. return this.stats.users;
  130. }
  131. /**
  132. * Updates of the current stats is requested, passing the new values.
  133. *
  134. * @param {Object} newStats - The new values used to update current one.
  135. * @private
  136. */
  137. _updateStats(newStats) {
  138. for (const userId in newStats) { // eslint-disable-line guard-for-in
  139. let speakerStatsToUpdate;
  140. const newParticipant = this.conference.getParticipantById(userId);
  141. // we want to ignore hidden participants
  142. if (!newParticipant || !newParticipant.isHidden()) {
  143. if (this.stats.users[userId]) {
  144. speakerStatsToUpdate = this.stats.users[userId];
  145. if (!speakerStatsToUpdate.getDisplayName()) {
  146. speakerStatsToUpdate
  147. .setDisplayName(newStats[userId].displayName);
  148. }
  149. } else {
  150. speakerStatsToUpdate = new SpeakerStats(
  151. userId, newStats[userId].displayName);
  152. this.stats.users[userId] = speakerStatsToUpdate;
  153. speakerStatsToUpdate.markAsHasLeft();
  154. }
  155. }
  156. speakerStatsToUpdate.totalDominantSpeakerTime
  157. = newStats[userId].totalDominantSpeakerTime;
  158. speakerStatsToUpdate.setFacialExpressions(newStats[userId].facialExpressions);
  159. }
  160. }
  161. }