feat: Handle dominant speaker silence
This commit is contained in:
parent
81f5e68382
commit
f0a45a9976
|
@ -2291,7 +2291,9 @@ export default {
|
|||
|
||||
room.on(
|
||||
JitsiConferenceEvents.DOMINANT_SPEAKER_CHANGED,
|
||||
(dominant, previous) => APP.store.dispatch(dominantSpeakerChanged(dominant, previous, room)));
|
||||
(dominant, previous, silence) => {
|
||||
APP.store.dispatch(dominantSpeakerChanged(dominant, previous, Boolean(silence), room));
|
||||
});
|
||||
|
||||
room.on(
|
||||
JitsiConferenceEvents.CONFERENCE_CREATED_TIMESTAMP,
|
||||
|
|
|
@ -216,7 +216,9 @@ function _addConferenceListeners(conference, dispatch, state) {
|
|||
|
||||
conference.on(
|
||||
JitsiConferenceEvents.DOMINANT_SPEAKER_CHANGED,
|
||||
(dominant, previous) => dispatch(dominantSpeakerChanged(dominant, previous, conference)));
|
||||
(dominant, previous, silence) => {
|
||||
dispatch(dominantSpeakerChanged(dominant, previous, Boolean(silence), conference));
|
||||
});
|
||||
|
||||
conference.on(
|
||||
JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
* participant: {
|
||||
* conference: JitsiConference,
|
||||
* id: string,
|
||||
* previousSpeakers: Array<string>
|
||||
* previousSpeakers: Array<string>,
|
||||
* silence: boolean
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
|
|
|
@ -45,6 +45,7 @@ import { Participant } from './types';
|
|||
*
|
||||
* @param {string} dominantSpeaker - Participant ID of the dominant speaker.
|
||||
* @param {Array<string>} previousSpeakers - Participant IDs of the previous speakers.
|
||||
* @param {boolean} silence - Whether the dominant speaker is silent or not.
|
||||
* @param {JitsiConference} conference - The {@code JitsiConference} associated
|
||||
* with the participant identified by the specified {@code id}. Only the local
|
||||
* participant is allowed to not specify an associated {@code JitsiConference}
|
||||
|
@ -54,17 +55,20 @@ import { Participant } from './types';
|
|||
* participant: {
|
||||
* conference: JitsiConference,
|
||||
* id: string,
|
||||
* previousSpeakers: Array<string>
|
||||
* previousSpeakers: Array<string>,
|
||||
* silence: boolean
|
||||
* }
|
||||
* }}
|
||||
*/
|
||||
export function dominantSpeakerChanged(dominantSpeaker: string, previousSpeakers: string[], conference: any) {
|
||||
export function dominantSpeakerChanged(
|
||||
dominantSpeaker: string, previousSpeakers: string[], silence: boolean, conference: any) {
|
||||
return {
|
||||
type: DOMINANT_SPEAKER_CHANGED,
|
||||
participant: {
|
||||
conference,
|
||||
id: dominantSpeaker,
|
||||
previousSpeakers
|
||||
previousSpeakers,
|
||||
silence
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -111,9 +111,12 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
const { id } = action.participant;
|
||||
const state = store.getState();
|
||||
const participant = getLocalParticipant(state);
|
||||
const dominantSpeaker = getDominantSpeakerParticipant(state);
|
||||
const isLocal = participant && participant.id === id;
|
||||
|
||||
if (isLocal && hasRaisedHand(participant) && !getDisableRemoveRaisedHandOnFocus(state)) {
|
||||
if (isLocal && dominantSpeaker?.id !== id
|
||||
&& hasRaisedHand(participant)
|
||||
&& !getDisableRemoveRaisedHandOnFocus(state)) {
|
||||
store.dispatch(raiseHand(false));
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,8 @@ import {
|
|||
PARTICIPANT_ROLE_CHANGED,
|
||||
SET_LOADABLE_AVATAR_URL,
|
||||
getLocalParticipant,
|
||||
getParticipantById
|
||||
getParticipantById,
|
||||
getDominantSpeakerParticipant
|
||||
} from '../base/participants';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
import { getBaseUrl } from '../base/util';
|
||||
|
@ -38,6 +39,19 @@ declare var APP: Object;
|
|||
MiddlewareRegistry.register(store => next => action => {
|
||||
// We need to do these before executing the rest of the middelware chain
|
||||
switch (action.type) {
|
||||
case DOMINANT_SPEAKER_CHANGED: {
|
||||
const dominantSpeaker = getDominantSpeakerParticipant(store.getState());
|
||||
|
||||
if (dominantSpeaker?.id !== action.participant.id) {
|
||||
const result = next(action);
|
||||
|
||||
APP.API.notifyDominantSpeakerChanged(action.participant.id);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SET_LOADABLE_AVATAR_URL: {
|
||||
const { id, loadableAvatarUrl } = action.participant;
|
||||
const participant = getParticipantById(
|
||||
|
@ -115,10 +129,6 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
APP.API.notifyDataChannelOpened();
|
||||
break;
|
||||
|
||||
case DOMINANT_SPEAKER_CHANGED:
|
||||
APP.API.notifyDominantSpeakerChanged(action.participant.id);
|
||||
break;
|
||||
|
||||
case KICKED_OUT:
|
||||
APP.API.notifyKickedOut(
|
||||
{
|
||||
|
|
|
@ -236,8 +236,9 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
const stageFilmstrip = isStageFilmstripAvailable(state);
|
||||
const local = getLocalParticipant(state);
|
||||
const currentLayout = getCurrentLayout(state);
|
||||
const dominantSpeaker = getDominantSpeakerParticipant(state);
|
||||
|
||||
if (id === local.id || currentLayout === LAYOUTS.TILE_VIEW) {
|
||||
if (dominantSpeaker?.id === id || id === local.id || currentLayout === LAYOUTS.TILE_VIEW) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,8 @@ import {
|
|||
PARTICIPANT_JOINED,
|
||||
PARTICIPANT_LEFT,
|
||||
PIN_PARTICIPANT,
|
||||
getLocalParticipant
|
||||
getLocalParticipant,
|
||||
getDominantSpeakerParticipant
|
||||
} from '../base/participants';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
import { isTestModeEnabled } from '../base/testing';
|
||||
|
@ -28,12 +29,18 @@ import './subscriber';
|
|||
* @returns {Function}
|
||||
*/
|
||||
MiddlewareRegistry.register(store => next => action => {
|
||||
const result = next(action);
|
||||
|
||||
switch (action.type) {
|
||||
case DOMINANT_SPEAKER_CHANGED: {
|
||||
const state = store.getState();
|
||||
const localParticipant = getLocalParticipant(state);
|
||||
const dominantSpeaker = getDominantSpeakerParticipant(state);
|
||||
|
||||
|
||||
if (dominantSpeaker?.id === action.participant.id) {
|
||||
return next(action);
|
||||
}
|
||||
|
||||
const result = next(action);
|
||||
|
||||
if (isTestModeEnabled(state)) {
|
||||
logger.info(`Dominant speaker changed event for: ${action.participant.id}`);
|
||||
|
@ -43,17 +50,22 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
store.dispatch(selectParticipantInLargeVideo());
|
||||
}
|
||||
|
||||
break;
|
||||
return result;
|
||||
}
|
||||
case PARTICIPANT_JOINED:
|
||||
case PARTICIPANT_LEFT:
|
||||
case PIN_PARTICIPANT:
|
||||
case TOGGLE_DOCUMENT_EDITING:
|
||||
case TRACK_ADDED:
|
||||
case TRACK_REMOVED:
|
||||
case TRACK_REMOVED: {
|
||||
const result = next(action);
|
||||
|
||||
store.dispatch(selectParticipantInLargeVideo());
|
||||
break;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
const result = next(action);
|
||||
|
||||
return result;
|
||||
});
|
||||
|
|
|
@ -143,10 +143,12 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: any)
|
|||
}
|
||||
case DOMINANT_SPEAKER_CHANGED: {
|
||||
if (canSendRtcstatsData(state)) {
|
||||
const { id, previousSpeakers } = action.participant;
|
||||
const { id, previousSpeakers, silence } = action.participant;
|
||||
|
||||
RTCStats.sendDominantSpeakerData({ dominantSpeakerEndpoint: id,
|
||||
previousSpeakers });
|
||||
RTCStats.sendDominantSpeakerData({
|
||||
dominantSpeakerEndpoint: silence ? null : id,
|
||||
previousSpeakers
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ function on_message(event)
|
|||
= event.stanza:get_child('speakerstats', 'http://jitsi.org/jitmeet');
|
||||
if speakerStats then
|
||||
local roomAddress = speakerStats.attr.room;
|
||||
local silence = speakerStats.attr.silence == 'true';
|
||||
local room = get_room_from_jid(room_jid_match_rewrite(roomAddress));
|
||||
|
||||
if not room then
|
||||
|
@ -85,15 +86,15 @@ function on_message(event)
|
|||
local newDominantSpeaker = roomSpeakerStats[occupant.jid];
|
||||
local oldDominantSpeakerId = roomSpeakerStats['dominantSpeakerId'];
|
||||
|
||||
if oldDominantSpeakerId then
|
||||
if oldDominantSpeakerId and occupant.jid ~= oldDominantSpeakerId then
|
||||
local oldDominantSpeaker = roomSpeakerStats[oldDominantSpeakerId];
|
||||
if oldDominantSpeaker then
|
||||
oldDominantSpeaker:setDominantSpeaker(false);
|
||||
oldDominantSpeaker:setDominantSpeaker(false, false);
|
||||
end
|
||||
end
|
||||
|
||||
if newDominantSpeaker then
|
||||
newDominantSpeaker:setDominantSpeaker(true);
|
||||
newDominantSpeaker:setDominantSpeaker(true, silence);
|
||||
end
|
||||
|
||||
room.speakerStats['dominantSpeakerId'] = occupant.jid;
|
||||
|
@ -136,6 +137,8 @@ function new_SpeakerStats(nick, context_user)
|
|||
return setmetatable({
|
||||
totalDominantSpeakerTime = 0;
|
||||
_dominantSpeakerStart = 0;
|
||||
_isSilent = false;
|
||||
_isDominantSpeaker = false;
|
||||
nick = nick;
|
||||
context_user = context_user;
|
||||
displayName = nil;
|
||||
|
@ -154,24 +157,43 @@ end
|
|||
-- Changes the dominantSpeaker data for current occupant
|
||||
-- saves start time if it is new dominat speaker
|
||||
-- or calculates and accumulates time of speaking
|
||||
function SpeakerStats:setDominantSpeaker(isNowDominantSpeaker)
|
||||
function SpeakerStats:setDominantSpeaker(isNowDominantSpeaker, silence)
|
||||
-- log("debug", "set isDominant %s for %s", tostring(isNowDominantSpeaker), self.nick);
|
||||
|
||||
if not self:isDominantSpeaker() and isNowDominantSpeaker then
|
||||
self._dominantSpeakerStart = socket.gettime()*1000;
|
||||
elseif self:isDominantSpeaker() and not isNowDominantSpeaker then
|
||||
local now = socket.gettime()*1000;
|
||||
local timeElapsed = math.floor(now - self._dominantSpeakerStart);
|
||||
local now = socket.gettime()*1000;
|
||||
|
||||
self.totalDominantSpeakerTime
|
||||
= self.totalDominantSpeakerTime + timeElapsed;
|
||||
self._dominantSpeakerStart = 0;
|
||||
if not self:isDominantSpeaker() and isNowDominantSpeaker and not silence then
|
||||
self._dominantSpeakerStart = now;
|
||||
elseif self:isDominantSpeaker() then
|
||||
if not isNowDominantSpeaker then
|
||||
if not self._isSilent then
|
||||
local timeElapsed = math.floor(now - self._dominantSpeakerStart);
|
||||
|
||||
self.totalDominantSpeakerTime = self.totalDominantSpeakerTime + timeElapsed;
|
||||
self._dominantSpeakerStart = 0;
|
||||
end
|
||||
elseif self._isSilent and not silence then
|
||||
self._dominantSpeakerStart = now;
|
||||
elseif not self._isSilent and silence then
|
||||
local timeElapsed = math.floor(now - self._dominantSpeakerStart);
|
||||
|
||||
self.totalDominantSpeakerTime = self.totalDominantSpeakerTime + timeElapsed;
|
||||
self._dominantSpeakerStart = 0;
|
||||
end
|
||||
end
|
||||
|
||||
self._isDominantSpeaker = isNowDominantSpeaker;
|
||||
self._isSilent = silence;
|
||||
end
|
||||
|
||||
-- Returns true if the tracked user is currently a dominant speaker.
|
||||
function SpeakerStats:isDominantSpeaker()
|
||||
return self._dominantSpeakerStart > 0;
|
||||
return self._isDominantSpeaker;
|
||||
end
|
||||
|
||||
-- Returns true if the tracked user is currently silent.
|
||||
function SpeakerStats:isSilent()
|
||||
return self._isSilent;
|
||||
end
|
||||
--- End SpeakerStats
|
||||
|
||||
|
@ -225,7 +247,7 @@ function occupant_joined(event)
|
|||
if totalDominantSpeakerTime > 0 or room:get_occupant_jid(jid) == nil or values:isDominantSpeaker()
|
||||
or get_participant_expressions_count(faceExpressions) > 0 then
|
||||
-- before sending we need to calculate current dominant speaker state
|
||||
if values:isDominantSpeaker() then
|
||||
if values:isDominantSpeaker() and not values:isSilent() then
|
||||
local timeElapsed = math.floor(socket.gettime()*1000 - values._dominantSpeakerStart);
|
||||
totalDominantSpeakerTime = totalDominantSpeakerTime + timeElapsed;
|
||||
end
|
||||
|
@ -276,7 +298,7 @@ function occupant_leaving(event)
|
|||
|
||||
local speakerStatsForOccupant = room.speakerStats[occupant.jid];
|
||||
if speakerStatsForOccupant then
|
||||
speakerStatsForOccupant:setDominantSpeaker(false);
|
||||
speakerStatsForOccupant:setDominantSpeaker(false, false);
|
||||
|
||||
-- set display name
|
||||
local displayName = occupant:get_presence():get_child_text(
|
||||
|
|
Loading…
Reference in New Issue