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

statsEmitter.ts 5.3KB

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