您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

statsEmitter.js 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // @flow
  2. import _ from 'lodash';
  3. import {
  4. JitsiConnectionQualityEvents,
  5. JitsiE2ePingEvents
  6. } from '../base/lib-jitsi-meet';
  7. /**
  8. * Contains all the callbacks to be notified when stats are updated.
  9. *
  10. * {
  11. * userId: Function[]
  12. * }
  13. */
  14. const subscribers = {};
  15. /**
  16. * A singleton that acts as a pub/sub service for connection stat updates.
  17. */
  18. const statsEmitter = {
  19. /**
  20. * Have {@code statsEmitter} subscribe to stat updates from a given
  21. * conference.
  22. *
  23. * @param {JitsiConference} conference - The conference for which
  24. * {@code statsEmitter} should subscribe for stat updates.
  25. * @returns {void}
  26. */
  27. startListeningForStats(conference: Object) {
  28. conference.on(JitsiConnectionQualityEvents.LOCAL_STATS_UPDATED,
  29. stats => this._onStatsUpdated(conference.myUserId(), stats));
  30. conference.on(JitsiConnectionQualityEvents.REMOTE_STATS_UPDATED,
  31. (id, stats) => this._emitStatsUpdate(id, stats));
  32. conference.on(
  33. JitsiE2ePingEvents.E2E_RTT_CHANGED,
  34. (participant, e2eRtt) => {
  35. const stats = {
  36. e2eRtt,
  37. region: participant.getProperty('region')
  38. };
  39. this._emitStatsUpdate(participant.getId(), stats);
  40. });
  41. },
  42. /**
  43. * Add a subscriber to be notified when stats are updated for a specified
  44. * user id.
  45. *
  46. * @param {string} id - The user id whose stats updates are of interest.
  47. * @param {Function} callback - The function to invoke when stats for the
  48. * user have been updated.
  49. * @returns {void}
  50. */
  51. subscribeToClientStats(id: ?string, callback: Function) {
  52. if (!id) {
  53. return;
  54. }
  55. if (!subscribers[id]) {
  56. subscribers[id] = [];
  57. }
  58. subscribers[id].push(callback);
  59. },
  60. /**
  61. * Remove a subscriber that is listening for stats updates for a specified
  62. * user id.
  63. *
  64. * @param {string} id - The user id whose stats updates are no longer of
  65. * interest.
  66. * @param {Function} callback - The function that is currently subscribed to
  67. * stat updates for the specified user id.
  68. * @returns {void}
  69. */
  70. unsubscribeToClientStats(id: string, callback: Function) {
  71. if (!subscribers[id]) {
  72. return;
  73. }
  74. const filteredSubscribers = subscribers[id].filter(
  75. subscriber => subscriber !== callback);
  76. if (filteredSubscribers.length) {
  77. subscribers[id] = filteredSubscribers;
  78. } else {
  79. delete subscribers[id];
  80. }
  81. },
  82. /**
  83. * Emit a stat update to all those listening for a specific user's
  84. * connection stats.
  85. *
  86. * @param {string} id - The user id the stats are associated with.
  87. * @param {Object} stats - New connection stats for the user.
  88. * @returns {void}
  89. */
  90. _emitStatsUpdate(id: string, stats: Object = {}) {
  91. const callbacks = subscribers[id] || [];
  92. callbacks.forEach(callback => {
  93. callback(stats);
  94. });
  95. },
  96. /**
  97. * Emit a stat update to all those listening for local stat updates. Will
  98. * also update listeners of remote user stats of changes related to their
  99. * stats.
  100. *
  101. * @param {string} localUserId - The user id for the local user.
  102. * @param {Object} stats - Connection stats for the local user as provided
  103. * by the library.
  104. * @returns {void}
  105. */
  106. _onStatsUpdated(localUserId: string, stats: Object) {
  107. const allUserFramerates = stats.framerate || {};
  108. const allUserResolutions = stats.resolution || {};
  109. const allUserCodecs = stats.codec || {};
  110. // FIXME resolution and framerate are maps keyed off of user ids with
  111. // stat values. Receivers of stats expect resolution and framerate to
  112. // be primitives, not maps, so here we override the 'lib-jitsi-meet'
  113. // stats objects.
  114. const modifiedLocalStats = Object.assign({}, stats, {
  115. framerate: allUserFramerates[localUserId],
  116. resolution: allUserResolutions[localUserId],
  117. codec: allUserCodecs[localUserId]
  118. });
  119. this._emitStatsUpdate(localUserId, modifiedLocalStats);
  120. // Get all the unique user ids from the framerate and resolution stats
  121. // and update remote user stats as needed.
  122. const framerateUserIds = Object.keys(allUserFramerates);
  123. const resolutionUserIds = Object.keys(allUserResolutions);
  124. const codecUserIds = Object.keys(allUserCodecs);
  125. _.union(framerateUserIds, resolutionUserIds, codecUserIds)
  126. .filter(id => id !== localUserId)
  127. .forEach(id => {
  128. const remoteUserStats = {};
  129. const framerate = allUserFramerates[id];
  130. if (framerate) {
  131. remoteUserStats.framerate = framerate;
  132. }
  133. const resolution = allUserResolutions[id];
  134. if (resolution) {
  135. remoteUserStats.resolution = resolution;
  136. }
  137. const codec = allUserCodecs[id];
  138. if (codec) {
  139. remoteUserStats.codec = codec;
  140. }
  141. this._emitStatsUpdate(id, remoteUserStats);
  142. });
  143. }
  144. };
  145. export default statsEmitter;