diff --git a/src/components/RightSidebar/Participants/Participant.vue b/src/components/RightSidebar/Participants/Participant.vue index aeae82f0c3f..aa1319d3608 100644 --- a/src/components/RightSidebar/Participants/Participant.vue +++ b/src/components/RightSidebar/Participants/Participant.vue @@ -80,7 +80,7 @@
(token, attendeeId) => { - if (!state.speaking[token]) { - return undefined - } - - return state.speaking[token][attendeeId] + getParticipantSpeakingInformation: (state) => (attendeeId) => { + return state.speaking[attendeeId] }, /** @@ -410,30 +406,55 @@ const mutations = { * * @param {object} state - current store state. * @param {object} data - the wrapping object. - * @param {string} data.token - the conversation token participant is speaking in. * @param {string} data.attendeeId - the attendee ID of the participant in conversation. * @param {boolean} data.speaking - whether the participant is speaking or not */ - setSpeaking(state, { token, attendeeId, speaking }) { + setSpeaking(state, { attendeeId, speaking }) { // create a dummy object for current call - if (!state.speaking[token]) { - Vue.set(state.speaking, token, {}) + if (!state.speaking[attendeeId]) { + Vue.set(state.speaking, attendeeId, { speaking, lastTimestamp: Date.now(), totalCountedTime: 0 }) } - if (!state.speaking[token][attendeeId]) { - Vue.set(state.speaking[token], attendeeId, { speaking: null, lastTimestamp: 0, totalCountedTime: 0 }) + state.speaking[attendeeId].speaking = speaking + }, + + /** + * Tracks the interval id to update speaking information for a current call. + * + * @param {object} state - current store state. + * @param {number} interval - interval id. + */ + setSpeakingInterval(state, interval) { + Vue.set(state, 'speakingInterval', interval) + }, + + /** + * Update speaking information for a participant. + * + * @param {object} state - current store state. + * @param {object} data - the wrapping object. + * @param {string} data.attendeeId - the attendee ID of the participant in conversation. + * @param {boolean} data.speaking - whether the participant is speaking or not + */ + updateTimeSpeaking(state, { attendeeId, speaking }) { + if (!state.speaking[attendeeId]) { + return } const currentTimestamp = Date.now() - const currentSpeakingState = state.speaking[token][attendeeId].speaking - - if (!currentSpeakingState && speaking) { - state.speaking[token][attendeeId].speaking = true - state.speaking[token][attendeeId].lastTimestamp = currentTimestamp - } else if (currentSpeakingState && !speaking) { - // when speaking has stopped, update the total talking time - state.speaking[token][attendeeId].speaking = false - state.speaking[token][attendeeId].totalCountedTime += (currentTimestamp - state.speaking[token][attendeeId].lastTimestamp) + const currentSpeakingState = state.speaking[attendeeId].speaking + + if (!currentSpeakingState && !speaking) { + // false -> false, no updates + return + } + + if (currentSpeakingState) { + // true -> false / true -> true, participant is still speaking or finished to speak, update total time + state.speaking[attendeeId].totalCountedTime += (currentTimestamp - state.speaking[attendeeId].lastTimestamp) } + + // false -> true / true -> false / true -> true, update timestamp of last check / signal + state.speaking[attendeeId].lastTimestamp = currentTimestamp }, /** @@ -441,11 +462,14 @@ const mutations = { * (including cases when the call ends for everyone). * * @param {object} state - current store state. - * @param {object} data - the wrapping object. - * @param {string} data.token - the conversation token. */ - purgeSpeakingStore(state, { token }) { - Vue.delete(state.speaking, token) + purgeSpeakingStore(state) { + Vue.set(state, 'speaking', {}) + + if (state.speakingInterval) { + clearInterval(state.speakingInterval) + Vue.set(state, 'speakingInterval', null) + } }, /** @@ -1036,12 +1060,33 @@ const actions = { } }, - setSpeaking(context, { token, attendeeId, speaking }) { - context.commit('setSpeaking', { token, attendeeId, speaking }) + setSpeaking(context, { attendeeId, speaking }) { + // We should update time before speaking state, to be able to check previous state + context.commit('updateTimeSpeaking', { attendeeId, speaking }) + context.commit('setSpeaking', { attendeeId, speaking }) + + if (!context.state.speakingInterval && speaking) { + const interval = setInterval(() => { + context.dispatch('updateIntervalTimeSpeaking') + }, 1000) + context.commit('setSpeakingInterval', interval) + } + }, + + updateIntervalTimeSpeaking(context) { + if (!context.state.speaking || !context.state.speakingInterval) { + return + } + + for (const attendeeId in context.state.speaking) { + if (context.state.speaking[attendeeId].speaking) { + context.commit('updateTimeSpeaking', { attendeeId, speaking: true }) + } + } }, - purgeSpeakingStore(context, { token }) { - context.commit('purgeSpeakingStore', { token }) + purgeSpeakingStore(context) { + context.commit('purgeSpeakingStore') }, processDialOutAnswer(context, { callid }) { diff --git a/src/utils/webrtc/SpeakingStatusHandler.js b/src/utils/webrtc/SpeakingStatusHandler.js index 9201f36583e..63bb40e0af2 100644 --- a/src/utils/webrtc/SpeakingStatusHandler.js +++ b/src/utils/webrtc/SpeakingStatusHandler.js @@ -81,7 +81,7 @@ export default class SpeakingStatusHandler { callParticipantModel.off('change:stoppedSpeaking', this.#handleSpeakingBound) }) - this.#store.dispatch('purgeSpeakingStore', { token: this.#store.getters.getToken() }) + this.#store.dispatch('purgeSpeakingStore') } /** @@ -114,7 +114,6 @@ export default class SpeakingStatusHandler { */ #handleLocalSpeaking(localMediaModel, speaking) { this.#store.dispatch('setSpeaking', { - token: this.#store.getters.getToken(), attendeeId: this.#store.getters.getAttendeeId(), speaking, }) @@ -126,7 +125,6 @@ export default class SpeakingStatusHandler { */ #handleLocalPeerId() { this.#store.dispatch('setSpeaking', { - token: this.#store.getters.getToken(), attendeeId: this.#store.getters.getAttendeeId(), speaking: this.#localMediaModel.attributes.speaking, }) @@ -149,7 +147,6 @@ export default class SpeakingStatusHandler { } this.#store.dispatch('setSpeaking', { - token: this.#store.getters.getToken(), attendeeId, speaking, })