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

mod_speakerstats_component.lua 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. local get_room_from_jid = module:require "util".get_room_from_jid;
  2. local jid_resource = require "util.jid".resource;
  3. local ext_events = module:require "ext_events"
  4. local st = require "util.stanza";
  5. local socket = require "socket";
  6. local json = require "util.json";
  7. local muc_component_host = module:get_option_string("muc_component");
  8. if muc_component_host == nil then
  9. log("error", "No muc_component specified. No muc to operate on!");
  10. return;
  11. end
  12. local muc_module = module:context("conference."..muc_component_host);
  13. if muc_module == nil then
  14. log("error", "No such muc found, check muc_component config.");
  15. return;
  16. end
  17. log("debug", "Starting speakerstats for %s", muc_component_host);
  18. -- receives messages from client currently connected to the room
  19. -- clients indicates their own dominant speaker events
  20. function on_message(event)
  21. -- Check the type of the incoming stanza to avoid loops:
  22. if event.stanza.attr.type == "error" then
  23. return; -- We do not want to reply to these, so leave.
  24. end
  25. local speakerStats
  26. = event.stanza:get_child('speakerstats', 'http://jitsi.org/jitmeet');
  27. if speakerStats then
  28. local roomAddress = speakerStats.attr.room;
  29. local room = get_room_from_jid(roomAddress);
  30. if not room then
  31. log("warn", "No room found %s", roomAddress);
  32. return false;
  33. end
  34. local roomSpeakerStats = room.speakerStats;
  35. local from = event.stanza.attr.from;
  36. local occupant = room:get_occupant_by_real_jid(from);
  37. if not occupant then
  38. log("warn", "No occupant %s found for %s", from, roomAddress);
  39. return false;
  40. end
  41. local newDominantSpeaker = roomSpeakerStats[occupant.jid];
  42. local oldDominantSpeakerId = roomSpeakerStats['dominantSpeakerId'];
  43. if oldDominantSpeakerId then
  44. roomSpeakerStats[oldDominantSpeakerId]:setIsDominantSpeaker(false);
  45. end
  46. if newDominantSpeaker then
  47. newDominantSpeaker:setIsDominantSpeaker(true);
  48. end
  49. room.speakerStats['dominantSpeakerId'] = occupant.jid;
  50. end
  51. return true
  52. end
  53. --- Start SpeakerStats implementation
  54. local SpeakerStats = {};
  55. SpeakerStats.__index = SpeakerStats;
  56. function new_SpeakerStats(nick)
  57. return setmetatable({
  58. totalDominantSpeakerTime = 0;
  59. _dominantSpeakerStart = nil;
  60. _isDominantSpeaker = false;
  61. nick = nick;
  62. displayName = nil;
  63. }, SpeakerStats);
  64. end
  65. -- Changes the dominantSpeaker data for current occupant
  66. -- saves start time if it is new dominat speaker
  67. -- or calculates and accumulates time of speaking
  68. function SpeakerStats:setIsDominantSpeaker(isNowDominantSpeaker)
  69. log("debug",
  70. "set isDominant %s for %s", tostring(isNowDominantSpeaker), self.nick);
  71. if not self._isDominantSpeaker and isNowDominantSpeaker then
  72. self._dominantSpeakerStart = socket.gettime()*1000;
  73. elseif self._isDominantSpeaker and not isNowDominantSpeaker then
  74. local now = socket.gettime()*1000;
  75. local timeElapsed = math.floor(now - (self._dominantSpeakerStart or 0));
  76. self.totalDominantSpeakerTime
  77. = self.totalDominantSpeakerTime + timeElapsed;
  78. self._dominantSpeakerStart = nil;
  79. end
  80. self._isDominantSpeaker = isNowDominantSpeaker;
  81. end
  82. --- End SpeakerStats
  83. -- create speakerStats for the room
  84. function room_created(event)
  85. local room = event.room;
  86. room.speakerStats = {};
  87. end
  88. -- Create SpeakerStats object for the joined user
  89. function occupant_joined(event)
  90. local room = event.room;
  91. local occupant = event.occupant;
  92. local nick = jid_resource(occupant.nick);
  93. if room.speakerStats then
  94. -- lets send the current speaker stats to that user, so he can update
  95. -- its local stats
  96. if next(room.speakerStats) ~= nil then
  97. local users_json = {};
  98. for jid, values in pairs(room.speakerStats) do
  99. -- skip reporting those without a nick('dominantSpeakerId')
  100. -- and skip focus if sneaked into the table
  101. if values.nick ~= nil and values.nick ~= 'focus' then
  102. local resultSpeakerStats = {};
  103. local totalDominantSpeakerTime
  104. = values.totalDominantSpeakerTime;
  105. -- before sending we need to calculate current dominant speaker
  106. -- state
  107. if values._dominantSpeakerStart ~= nil then
  108. local timeElapsed = math.floor(
  109. socket.gettime()*1000
  110. - (values._dominantSpeakerStart or 0));
  111. totalDominantSpeakerTime = totalDominantSpeakerTime
  112. + timeElapsed;
  113. end
  114. resultSpeakerStats.displayName = values.displayName;
  115. resultSpeakerStats.totalDominantSpeakerTime
  116. = totalDominantSpeakerTime;
  117. users_json[values.nick] = resultSpeakerStats;
  118. end
  119. end
  120. local body_json = {};
  121. body_json.type = 'speakerstats';
  122. body_json.users = users_json;
  123. local stanza = st.message({
  124. from = module.host;
  125. to = occupant.jid; })
  126. :tag("json-message", {xmlns='http://jitsi.org/jitmeet'})
  127. :text(json.encode(body_json)):up();
  128. room:route_stanza(stanza);
  129. end
  130. room.speakerStats[occupant.jid] = new_SpeakerStats(nick);
  131. end
  132. end
  133. -- Occupant left set its dominant speaker to false and update the store the
  134. -- display name
  135. function occupant_leaving(event)
  136. local room = event.room;
  137. local occupant = event.occupant;
  138. local speakerStatsForOccupant = room.speakerStats[occupant.jid];
  139. if speakerStatsForOccupant then
  140. speakerStatsForOccupant:setIsDominantSpeaker(false);
  141. -- set display name
  142. local displayName = occupant:get_presence():get_child_text(
  143. 'nick', 'http://jabber.org/protocol/nick');
  144. speakerStatsForOccupant.displayName = displayName;
  145. end
  146. end
  147. -- Conference ended, send speaker stats
  148. function room_destroyed(event)
  149. local room = event.room;
  150. ext_events.speaker_stats(room, room.speakerStats);
  151. end
  152. module:hook("message/host", on_message);
  153. muc_module:hook("muc-room-created", room_created, -1);
  154. muc_module:hook("muc-occupant-joined", occupant_joined, -1);
  155. muc_module:hook("muc-occupant-pre-leave", occupant_leaving, -1);
  156. muc_module:hook("muc-room-destroyed", room_destroyed, -1);