[IMP] mail: make the mute and deafen button behavior more intuitive
* When a user is already muted when setting their state as deafened the mute state should remain after the deafen state is removed. * When a user clicks the microphone (mute/unmute) button while being in the deaf state, the user should end up undeafen and unmute. task-2720026 closes odoo/odoo#82197 Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
This commit is contained in:
+1
-1
@@ -49,7 +49,7 @@
|
||||
</t>
|
||||
</span>
|
||||
<div class="o_RtcCallParticipantCard_overlayTop">
|
||||
<t t-if="callParticipantCard.rtcSession.isSelfMuted">
|
||||
<t t-if="callParticipantCard.rtcSession.isSelfMuted and !callParticipantCard.rtcSession.isDeaf">
|
||||
<span class="o_RtcCallParticipantCard_overlayTopElement" t-att-class="{'o-isMinimized': callParticipantCard.isMinimized }" title="muted" aria-label="muted">
|
||||
<i class="fa fa-microphone-slash"/>
|
||||
</span>
|
||||
|
||||
@@ -6,19 +6,19 @@
|
||||
<t t-if="rtcController and messaging">
|
||||
<div class="o_RtcController_buttons">
|
||||
<t t-if="rtcController.callViewer.threadView.thread.rtc and messaging.rtc.currentRtcSession">
|
||||
<t t-if="messaging.rtc.currentRtcSession.isSelfMuted"><t t-set="microphoneTitle">Unmute</t></t>
|
||||
<t t-if="messaging.rtc.currentRtcSession.isMute"><t t-set="microphoneTitle">Unmute</t></t>
|
||||
<t t-else=""><t t-set="microphoneTitle">Mute</t></t>
|
||||
<button class="o_RtcController_button"
|
||||
t-att-class="{ 'o-isActive': !messaging.rtc.currentRtcSession.isSelfMuted, 'o-isSmall': rtcController.isSmall }"
|
||||
t-att-class="{ 'o-isActive': !messaging.rtc.currentRtcSession.isMute, 'o-isSmall': rtcController.isSmall }"
|
||||
t-att-aria-label="microphoneTitle"
|
||||
t-att-title="microphoneTitle"
|
||||
t-on-click="rtcController.onClickMicrophone">
|
||||
<div class="o_RtcController_buttonIconWrapper" t-att-class="{ 'o-isSmall': rtcController.isSmall }">
|
||||
<i class="fa" t-att-class="{
|
||||
'fa-lg': !rtcController.isSmall,
|
||||
'fa-microphone': !messaging.rtc.currentRtcSession.isSelfMuted,
|
||||
'fa-microphone-slash': messaging.rtc.currentRtcSession.isSelfMuted,
|
||||
'text-danger': messaging.rtc.currentRtcSession.isSelfMuted,
|
||||
'fa-microphone': !messaging.rtc.currentRtcSession.isMute,
|
||||
'fa-microphone-slash': messaging.rtc.currentRtcSession.isMute,
|
||||
'text-danger': messaging.rtc.currentRtcSession.isMute,
|
||||
}"/>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
@@ -98,6 +98,9 @@ registerModel({
|
||||
},
|
||||
},
|
||||
recordMethods: {
|
||||
async deafen() {
|
||||
await this._setDeafState(true);
|
||||
},
|
||||
/**
|
||||
* Removes and disconnects all the peerConnections that are not current members of the call.
|
||||
*
|
||||
@@ -198,6 +201,9 @@ registerModel({
|
||||
await this._toggleVideoBroadcast({ type: videoType });
|
||||
}
|
||||
},
|
||||
async mute() {
|
||||
await this._setMuteState(true);
|
||||
},
|
||||
/**
|
||||
* Resets the state of the model and cleanly ends all connections and
|
||||
* streams.
|
||||
@@ -234,18 +240,13 @@ registerModel({
|
||||
/**
|
||||
* Mutes and unmutes the microphone, will not unmute if deaf.
|
||||
*
|
||||
* @param {Object} [param0]
|
||||
* @param {string} [param0.requestAudioDevice] true if requesting the audio input device
|
||||
* from the user
|
||||
*/
|
||||
async toggleMicrophone({ requestAudioDevice = true } = {}) {
|
||||
const shouldMute = this.currentRtcSession.isDeaf || !this.currentRtcSession.isSelfMuted;
|
||||
this.currentRtcSession.updateAndBroadcast({ isSelfMuted: shouldMute || !this.audioTrack });
|
||||
if (!this.audioTrack && !shouldMute && requestAudioDevice) {
|
||||
// if we don't have an audioTrack, we try to request it again
|
||||
await this.updateLocalAudioTrack(true);
|
||||
async toggleMicrophone() {
|
||||
if (this.currentRtcSession.isMute) {
|
||||
await this.unmute();
|
||||
} else {
|
||||
await this.mute();
|
||||
}
|
||||
await this.async(() => this._updateLocalAudioTrackEnabledState());
|
||||
},
|
||||
/**
|
||||
* toggles screen broadcasting to peers.
|
||||
@@ -259,6 +260,17 @@ registerModel({
|
||||
async toggleUserVideo() {
|
||||
this._toggleVideoBroadcast({ type: 'user-video' });
|
||||
},
|
||||
async undeafen() {
|
||||
await this._setDeafState(false);
|
||||
},
|
||||
async unmute() {
|
||||
if (this.audioTrack) {
|
||||
await this._setMuteState(false);
|
||||
} else {
|
||||
// if we don't have an audioTrack, we try to request it again
|
||||
await this.updateLocalAudioTrack(true);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @param {Boolean} audio
|
||||
*/
|
||||
@@ -301,7 +313,7 @@ registerModel({
|
||||
await this.async(() => this._updateLocalAudioTrackEnabledState());
|
||||
});
|
||||
this.currentRtcSession.updateAndBroadcast({ isSelfMuted: false });
|
||||
audioTrack.enabled = !this.currentRtcSession.isSelfMuted && this.currentRtcSession.isTalking;
|
||||
audioTrack.enabled = !this.currentRtcSession.isMute && this.currentRtcSession.isTalking;
|
||||
this.update({ audioTrack });
|
||||
await this.async(() => this.updateVoiceActivation());
|
||||
for (const [token, peerConnection] of Object.entries(this._peerConnections)) {
|
||||
@@ -485,7 +497,10 @@ registerModel({
|
||||
type: 'peerToPeer',
|
||||
payload: {
|
||||
type: 'audio',
|
||||
state: { isTalking: this.currentRtcSession.isTalking, isSelfMuted: this.currentRtcSession.isSelfMuted },
|
||||
state: {
|
||||
isTalking: this.audioTrack && this.audioTrack.enabled,
|
||||
isSelfMuted: this.currentRtcSession.isSelfMuted,
|
||||
},
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
@@ -836,6 +851,26 @@ registerModel({
|
||||
];
|
||||
return JSON.stringify(Object.fromEntries(toLog.map(p => [p, dataChannel[p]])));
|
||||
},
|
||||
/**
|
||||
* @param {Boolean} isDeaf
|
||||
*/
|
||||
async _setDeafState(isDeaf) {
|
||||
this.currentRtcSession.updateAndBroadcast({ isDeaf });
|
||||
for (const session of this.messaging.models['RtcSession'].all()) {
|
||||
if (!session.audioElement) {
|
||||
continue;
|
||||
}
|
||||
session.audioElement.muted = isDeaf;
|
||||
}
|
||||
await this._updateLocalAudioTrackEnabledState();
|
||||
},
|
||||
/**
|
||||
* @param {Boolean} isSelfMuted
|
||||
*/
|
||||
async _setMuteState(isSelfMuted) {
|
||||
this.currentRtcSession.updateAndBroadcast({ isSelfMuted });
|
||||
await this._updateLocalAudioTrackEnabledState();
|
||||
},
|
||||
/**
|
||||
* Updates the "isTalking" state of the current user and sets the
|
||||
* enabled state of its audio track accordingly.
|
||||
@@ -851,7 +886,7 @@ registerModel({
|
||||
return;
|
||||
}
|
||||
this.currentRtcSession.update({ isTalking });
|
||||
if (!this.currentRtcSession.isSelfMuted) {
|
||||
if (!this.currentRtcSession.isMute) {
|
||||
await this._updateLocalAudioTrackEnabledState();
|
||||
}
|
||||
},
|
||||
@@ -928,8 +963,8 @@ registerModel({
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Sets the enabled property of the local audio track based on the
|
||||
* current session state. And notifies peers of the new audio state.
|
||||
* Sets the enabled property of the local audio track and notifies
|
||||
* peers of the new state.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
@@ -937,14 +972,14 @@ registerModel({
|
||||
if (!this.audioTrack) {
|
||||
return;
|
||||
}
|
||||
this.audioTrack.enabled = !this.currentRtcSession.isSelfMuted && this.currentRtcSession.isTalking;
|
||||
this.audioTrack.enabled = !this.currentRtcSession.isMute && this.currentRtcSession.isTalking;
|
||||
await this._notifyPeers(Object.keys(this._peerConnections), {
|
||||
event: 'trackChange',
|
||||
type: 'peerToPeer',
|
||||
payload: {
|
||||
type: 'audio',
|
||||
state: {
|
||||
isTalking: this.currentRtcSession.isTalking && !this.currentRtcSession.isSelfMuted,
|
||||
isTalking: this.audioTrack.enabled,
|
||||
isSelfMuted: this.currentRtcSession.isSelfMuted,
|
||||
isDeaf: this.currentRtcSession.isDeaf,
|
||||
},
|
||||
@@ -1119,19 +1154,22 @@ registerModel({
|
||||
if (!this.channel) {
|
||||
return;
|
||||
}
|
||||
if (this.messaging.userSetting.rtcConfigurationMenu.isRegisteringKey) {
|
||||
if (!this.messaging.userSetting.usePushToTalk || !this.messaging.userSetting.isPushToTalkKey(ev)) {
|
||||
return;
|
||||
}
|
||||
if (!this.messaging.userSetting.usePushToTalk || !this.messaging.userSetting.isPushToTalkKey(ev)) {
|
||||
if (this.currentRtcSession.isMute) {
|
||||
return;
|
||||
}
|
||||
if (this.messaging.userSetting.rtcConfigurationMenu.isRegisteringKey) {
|
||||
return;
|
||||
}
|
||||
if (this._pushToTalkTimeoutId) {
|
||||
browser.clearTimeout(this._pushToTalkTimeoutId);
|
||||
}
|
||||
if (!this.currentRtcSession.isTalking && !this.currentRtcSession.isSelfMuted) {
|
||||
if (!this.currentRtcSession.isTalking) {
|
||||
this.messaging.soundEffects.pushToTalk.play({ volume: 0.3 });
|
||||
this._setSoundBroadcast(true);
|
||||
}
|
||||
this._setSoundBroadcast(true);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
@@ -1147,7 +1185,7 @@ registerModel({
|
||||
if (!this.currentRtcSession.isTalking) {
|
||||
return;
|
||||
}
|
||||
if (!this.currentRtcSession.isSelfMuted) {
|
||||
if (!this.currentRtcSession.isMute) {
|
||||
this.messaging.soundEffects.pushToTalk.play({ volume: 0.3 });
|
||||
}
|
||||
this._pushToTalkTimeoutId = browser.setTimeout(
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@ registerModel({
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_computeIsTalking() {
|
||||
return Boolean(this.rtcSession && this.rtcSession.isTalking && !this.rtcSession.isSelfMuted);
|
||||
return Boolean(this.rtcSession && this.rtcSession.isTalking && !this.rtcSession.isMute);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
|
||||
@@ -29,13 +29,26 @@ registerModel({
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
async onClickDeafen(ev) {
|
||||
await this.messaging.rtc.currentRtcSession.toggleDeaf();
|
||||
if (this.messaging.rtc.currentRtcSession.isDeaf) {
|
||||
this.messaging.rtc.undeafen();
|
||||
} else {
|
||||
this.messaging.rtc.deafen();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
onClickMicrophone(ev) {
|
||||
this.messaging.rtc.toggleMicrophone();
|
||||
if (this.messaging.rtc.currentRtcSession.isMute) {
|
||||
if (this.messaging.rtc.currentRtcSession.isSelfMuted) {
|
||||
this.messaging.rtc.unmute();
|
||||
}
|
||||
if (this.messaging.rtc.currentRtcSession.isDeaf) {
|
||||
this.messaging.rtc.undeafen();
|
||||
}
|
||||
} else {
|
||||
this.messaging.rtc.mute();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @param {MouseEvent} ev
|
||||
|
||||
@@ -131,23 +131,10 @@ registerModel({
|
||||
if (!this.rtc) {
|
||||
return;
|
||||
}
|
||||
this.updateAndBroadcast({
|
||||
isDeaf: !this.isDeaf,
|
||||
});
|
||||
for (const session of this.messaging.models['RtcSession'].all()) {
|
||||
if (!session.audioElement) {
|
||||
continue;
|
||||
}
|
||||
session.audioElement.muted = this.isDeaf;
|
||||
}
|
||||
if (this.channel.rtc) {
|
||||
/**
|
||||
* Ensures that the state of the microphone matches the deaf state
|
||||
* and notifies peers.
|
||||
*/
|
||||
await this.async(() => this.channel.rtc.toggleMicrophone({
|
||||
requestAudioDevice: false,
|
||||
}));
|
||||
if (this.rtc.currentRtcSession.isDeaf) {
|
||||
await this.rtc.undeafen();
|
||||
} else {
|
||||
await this.rtc.deafen();
|
||||
}
|
||||
},
|
||||
/**
|
||||
@@ -198,6 +185,13 @@ registerModel({
|
||||
return `/mail/channel/${this.channel.id}/guest/${this.guest.id}/avatar_128?unique=${this.guest.name}`;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_computeIsMute() {
|
||||
return this.isSelfMuted || this.isDeaf;
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {boolean}
|
||||
@@ -354,6 +348,13 @@ registerModel({
|
||||
isSelfMuted: attr({
|
||||
default: false,
|
||||
}),
|
||||
/**
|
||||
* Determine whether current session is unable to speak.
|
||||
*/
|
||||
isMute: attr({
|
||||
compute: '_computeIsMute',
|
||||
default: false,
|
||||
}),
|
||||
/**
|
||||
* Determines if the session is a session of the current partner.
|
||||
* This can be true for many sessions, as one user can have multiple
|
||||
|
||||
Reference in New Issue
Block a user