From 8924fe7fbdb414f2001b43f8edd44e0e875602b2 Mon Sep 17 00:00:00 2001 From: Maksim Sukharev Date: Tue, 12 Mar 2024 15:00:20 +0100 Subject: [PATCH 1/2] fix(participants): move interval update of talking time counter to the store Signed-off-by: Maksim Sukharev --- .../RightSidebar/Participants/Participant.vue | 39 +++------- src/store/participantsStore.js | 75 +++++++++++++++++-- 2 files changed, 76 insertions(+), 38 deletions(-) diff --git a/src/components/RightSidebar/Participants/Participant.vue b/src/components/RightSidebar/Participants/Participant.vue index aeae82f0c3f..8a2d3d6807b 100644 --- a/src/components/RightSidebar/Participants/Participant.vue +++ b/src/components/RightSidebar/Participants/Participant.vue @@ -80,7 +80,7 @@
false, no updates + return + } + + if (currentSpeakingState) { + // true -> false / true -> true, participant is still speaking or finished to speak, update total time state.speaking[token][attendeeId].totalCountedTime += (currentTimestamp - state.speaking[token][attendeeId].lastTimestamp) } + + // false -> true / true -> false / true -> true, update timestamp of last check / signal + state.speaking[token][attendeeId].lastTimestamp = currentTimestamp }, /** @@ -445,7 +476,14 @@ const mutations = { * @param {string} data.token - the conversation token. */ purgeSpeakingStore(state, { token }) { - Vue.delete(state.speaking, token) + if (state.speaking[token]) { + Vue.delete(state.speaking, token) + } + + if (state.speakingInterval) { + clearInterval(state.speakingInterval) + Vue.set(state, 'speakingInterval', null) + } }, /** @@ -1037,7 +1075,28 @@ const actions = { }, setSpeaking(context, { token, attendeeId, speaking }) { + // We should update time before speaking state, to be able to check previous state + context.commit('updateTimeSpeaking', { token, attendeeId, speaking }) context.commit('setSpeaking', { token, attendeeId, speaking }) + + if (!context.state.speakingInterval && speaking) { + const interval = setInterval(() => { + context.dispatch('updateIntervalTimeSpeaking', { token }) + }, 1000) + context.commit('setSpeakingInterval', interval) + } + }, + + updateIntervalTimeSpeaking(context, { token }) { + if (!context.state.speaking[token] || !context.state.speakingInterval) { + return + } + + for (const attendeeId in context.state.speaking[token]) { + if (context.state.speaking[token][attendeeId].speaking) { + context.commit('updateTimeSpeaking', { token, attendeeId, speaking: true }) + } + } }, purgeSpeakingStore(context, { token }) { From 708d4f8456f60ff044723e4c597d8eb4ebfb7b6e Mon Sep 17 00:00:00 2001 From: Maksim Sukharev Date: Thu, 14 Mar 2024 10:35:23 +0100 Subject: [PATCH 2/2] fix(participants): flatten the store data for speaking state - we assume there's only one active call at the moment, and purge speaking data when leave call, so it's safe to store them without token Signed-off-by: Maksim Sukharev --- .../RightSidebar/Participants/Participant.vue | 2 +- src/store/participantsStore.js | 62 +++++++------------ src/utils/webrtc/SpeakingStatusHandler.js | 5 +- 3 files changed, 26 insertions(+), 43 deletions(-) diff --git a/src/components/RightSidebar/Participants/Participant.vue b/src/components/RightSidebar/Participants/Participant.vue index 8a2d3d6807b..aa1319d3608 100644 --- a/src/components/RightSidebar/Participants/Participant.vue +++ b/src/components/RightSidebar/Participants/Participant.vue @@ -704,7 +704,7 @@ export default { }, participantSpeakingInformation() { - return this.$store.getters.getParticipantSpeakingInformation(this.token, this.attendeeId) + return this.$store.getters.getParticipantSpeakingInformation(this.attendeeId) }, isParticipantSpeaking() { diff --git a/src/store/participantsStore.js b/src/store/participantsStore.js index 56242a1e89e..851461e6001 100644 --- a/src/store/participantsStore.js +++ b/src/store/participantsStore.js @@ -179,16 +179,11 @@ const getters = { * Gets the speaking information for the participant. * * @param {object} state - the state object. - * param {string} token - the conversation token. * param {number} attendeeId - attendee's ID for the participant in conversation. * @return {object|undefined} */ - getParticipantSpeakingInformation: (state) => (token, attendeeId) => { - if (!state.speaking[token]) { - return undefined - } - - return state.speaking[token][attendeeId] + getParticipantSpeakingInformation: (state) => (attendeeId) => { + return state.speaking[attendeeId] }, /** @@ -411,19 +406,15 @@ 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, lastTimestamp: Date.now(), totalCountedTime: 0 }) - } - state.speaking[token][attendeeId].speaking = speaking + state.speaking[attendeeId].speaking = speaking }, /** @@ -441,17 +432,16 @@ 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 */ - updateTimeSpeaking(state, { token, attendeeId, speaking }) { - if (!state.speaking[token]?.[attendeeId]) { + updateTimeSpeaking(state, { attendeeId, speaking }) { + if (!state.speaking[attendeeId]) { return } const currentTimestamp = Date.now() - const currentSpeakingState = state.speaking[token][attendeeId].speaking + const currentSpeakingState = state.speaking[attendeeId].speaking if (!currentSpeakingState && !speaking) { // false -> false, no updates @@ -460,11 +450,11 @@ const mutations = { if (currentSpeakingState) { // true -> false / true -> true, participant is still speaking or finished to speak, update total time - state.speaking[token][attendeeId].totalCountedTime += (currentTimestamp - state.speaking[token][attendeeId].lastTimestamp) + state.speaking[attendeeId].totalCountedTime += (currentTimestamp - state.speaking[attendeeId].lastTimestamp) } // false -> true / true -> false / true -> true, update timestamp of last check / signal - state.speaking[token][attendeeId].lastTimestamp = currentTimestamp + state.speaking[attendeeId].lastTimestamp = currentTimestamp }, /** @@ -472,13 +462,9 @@ 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 }) { - if (state.speaking[token]) { - Vue.delete(state.speaking, token) - } + purgeSpeakingStore(state) { + Vue.set(state, 'speaking', {}) if (state.speakingInterval) { clearInterval(state.speakingInterval) @@ -1074,33 +1060,33 @@ const actions = { } }, - setSpeaking(context, { token, attendeeId, speaking }) { + setSpeaking(context, { attendeeId, speaking }) { // We should update time before speaking state, to be able to check previous state - context.commit('updateTimeSpeaking', { token, attendeeId, speaking }) - context.commit('setSpeaking', { token, attendeeId, speaking }) + context.commit('updateTimeSpeaking', { attendeeId, speaking }) + context.commit('setSpeaking', { attendeeId, speaking }) if (!context.state.speakingInterval && speaking) { const interval = setInterval(() => { - context.dispatch('updateIntervalTimeSpeaking', { token }) + context.dispatch('updateIntervalTimeSpeaking') }, 1000) context.commit('setSpeakingInterval', interval) } }, - updateIntervalTimeSpeaking(context, { token }) { - if (!context.state.speaking[token] || !context.state.speakingInterval) { + updateIntervalTimeSpeaking(context) { + if (!context.state.speaking || !context.state.speakingInterval) { return } - for (const attendeeId in context.state.speaking[token]) { - if (context.state.speaking[token][attendeeId].speaking) { - context.commit('updateTimeSpeaking', { token, attendeeId, speaking: true }) + 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, })