From 11f2e7291e469763d65bdaf9f609f395a830598f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BC=D1=8F=D0=BD=20=D0=9C=D0=B8=D0=BD=D0=BA?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Tue, 23 Jul 2019 21:56:05 +0100 Subject: [PATCH] Talk while muted sound notification (#4473) * Moves talk while muted as a new feature. * Adds sound notification for talk while muted. * Reorder imports and changes the dispatch of the notification. * Introduces sounds.js for talk while muted. --- conference.js | 23 +------ react/features/app/components/App.web.js | 1 + .../features/talk-while-muted/actionTypes.js | 12 ++++ react/features/talk-while-muted/actions.js | 21 ++++++ react/features/talk-while-muted/constants.js | 6 ++ react/features/talk-while-muted/index.js | 4 ++ react/features/talk-while-muted/middleware.js | 63 ++++++++++++++++++ react/features/talk-while-muted/reducer.js | 17 +++++ react/features/talk-while-muted/sounds.js | 6 ++ sounds/talkWhileMuted.mp3 | Bin 0 -> 9613 bytes webpack.config.js | 1 + 11 files changed, 132 insertions(+), 22 deletions(-) create mode 100644 react/features/talk-while-muted/actionTypes.js create mode 100644 react/features/talk-while-muted/actions.js create mode 100644 react/features/talk-while-muted/constants.js create mode 100644 react/features/talk-while-muted/index.js create mode 100644 react/features/talk-while-muted/middleware.js create mode 100644 react/features/talk-while-muted/reducer.js create mode 100644 react/features/talk-while-muted/sounds.js create mode 100644 sounds/talkWhileMuted.mp3 diff --git a/conference.js b/conference.js index 0539f5e8e..904737c96 100644 --- a/conference.js +++ b/conference.js @@ -78,10 +78,7 @@ import { setVideoAvailable, setVideoMuted } from './react/features/base/media'; -import { - hideNotification, - showNotification -} from './react/features/notifications'; +import { showNotification } from './react/features/notifications'; import { dominantSpeakerChanged, getLocalParticipant, @@ -1798,30 +1795,12 @@ export default { APP.UI.setAudioLevel(id, newLvl); }); - // we store the last start muted notification id that we showed, - // so we can hide it when unmuted mic is detected - let lastNotificationId; - room.on(JitsiConferenceEvents.TRACK_MUTE_CHANGED, (track, participantThatMutedUs) => { if (participantThatMutedUs) { APP.store.dispatch(participantMutedUs(participantThatMutedUs)); } - - if (lastNotificationId && track.isAudioTrack() && track.isLocal() && !track.isMuted()) { - APP.store.dispatch(hideNotification(lastNotificationId)); - lastNotificationId = undefined; - } }); - room.on(JitsiConferenceEvents.TALK_WHILE_MUTED, () => { - const action = APP.store.dispatch(showNotification({ - titleKey: 'toolbar.talkWhileMutedPopup', - customActionNameKey: 'notify.unmute', - customActionHandler: muteLocalAudio.bind(this, false) - })); - - lastNotificationId = action.uid; - }); room.on(JitsiConferenceEvents.SUBJECT_CHANGED, subject => APP.store.dispatch(conferenceSubjectChanged(subject))); diff --git a/react/features/app/components/App.web.js b/react/features/app/components/App.web.js index 56509b9c8..dad4a4989 100644 --- a/react/features/app/components/App.web.js +++ b/react/features/app/components/App.web.js @@ -10,6 +10,7 @@ import '../../chat'; import '../../external-api'; import '../../power-monitor'; import '../../room-lock'; +import '../../talk-while-muted'; import '../../video-layout'; import { AbstractApp } from './AbstractApp'; diff --git a/react/features/talk-while-muted/actionTypes.js b/react/features/talk-while-muted/actionTypes.js new file mode 100644 index 000000000..6bc5d6971 --- /dev/null +++ b/react/features/talk-while-muted/actionTypes.js @@ -0,0 +1,12 @@ +/** + * The type of Redux action which sets the pending notification UID + * to use it for when hiding the notification is necessary, or unsets it when + * undefined (or no param) is passed. + * + * { + * type: SET_CURRENT_NOTIFICATION_UID, + * uid: ?number + * } + * @public + */ +export const SET_CURRENT_NOTIFICATION_UID = 'SET_CURRENT_NOTIFICATION_UID'; diff --git a/react/features/talk-while-muted/actions.js b/react/features/talk-while-muted/actions.js new file mode 100644 index 000000000..95a234582 --- /dev/null +++ b/react/features/talk-while-muted/actions.js @@ -0,0 +1,21 @@ +// @flow + +import { SET_CURRENT_NOTIFICATION_UID } from './actionTypes'; + +/** + * Sets UID of the the pending notification to use it when hiding + * the notification is necessary, or unsets it when undefined (or no param) is + * passed. + * + * @param {?number} uid - The UID of the notification. + * @returns {{ + * type: SET_CURRENT_NOTIFICATION_UID, + * uid: number + * }} + */ +export function setCurrentNotificationUid(uid: ?number) { + return { + type: SET_CURRENT_NOTIFICATION_UID, + uid + }; +} diff --git a/react/features/talk-while-muted/constants.js b/react/features/talk-while-muted/constants.js new file mode 100644 index 000000000..1f4d5b612 --- /dev/null +++ b/react/features/talk-while-muted/constants.js @@ -0,0 +1,6 @@ +/** + * The identifier of the sound to be played when we got event for talking while muted. + * + * @type {string} + */ +export const TALK_WHILE_MUTED_SOUND_ID = 'TALK_WHILE_MUTED_SOUND_ID'; diff --git a/react/features/talk-while-muted/index.js b/react/features/talk-while-muted/index.js new file mode 100644 index 000000000..d040422d0 --- /dev/null +++ b/react/features/talk-while-muted/index.js @@ -0,0 +1,4 @@ +// @flow + +import './middleware'; +import './reducer'; diff --git a/react/features/talk-while-muted/middleware.js b/react/features/talk-while-muted/middleware.js new file mode 100644 index 000000000..ff73845f5 --- /dev/null +++ b/react/features/talk-while-muted/middleware.js @@ -0,0 +1,63 @@ +// @flow + +import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app'; +import { CONFERENCE_JOINED } from '../base/conference'; +import { JitsiConferenceEvents } from '../base/lib-jitsi-meet'; +import { setAudioMuted } from '../base/media'; +import { MiddlewareRegistry } from '../base/redux'; +import { playSound, registerSound, unregisterSound } from '../base/sounds'; +import { + hideNotification, + showNotification +} from '../notifications'; + +import { setCurrentNotificationUid } from './actions'; +import { TALK_WHILE_MUTED_SOUND_ID } from './constants'; +import { TALK_WHILE_MUTED_SOUND_FILE } from './sounds'; + +MiddlewareRegistry.register(store => next => action => { + const result = next(action); + const { dispatch, getState } = store; + const { conference } = action; + + switch (action.type) { + case APP_WILL_MOUNT: + dispatch(registerSound(TALK_WHILE_MUTED_SOUND_ID, TALK_WHILE_MUTED_SOUND_FILE)); + break; + case APP_WILL_UNMOUNT: + dispatch(unregisterSound(TALK_WHILE_MUTED_SOUND_ID)); + break; + + case CONFERENCE_JOINED: { + conference.on( + JitsiConferenceEvents.TRACK_MUTE_CHANGED, + track => { + const { currentNotificationUid } = getState()['features/talk-while-muted']; + + if (currentNotificationUid && track.isAudioTrack() && track.isLocal() && !track.isMuted()) { + dispatch(hideNotification(currentNotificationUid)); + dispatch(setCurrentNotificationUid()); + } + }); + conference.on( + JitsiConferenceEvents.TALK_WHILE_MUTED, () => { + const notification = showNotification({ + titleKey: 'toolbar.talkWhileMutedPopup', + customActionNameKey: 'notify.unmute', + customActionHandler: () => dispatch(setAudioMuted(false)) + }); + + dispatch(notification); + + dispatch(playSound(TALK_WHILE_MUTED_SOUND_ID)); + + // we store the last start muted notification id that we showed, + // so we can hide it when unmuted mic is detected + dispatch(setCurrentNotificationUid(notification.uid)); + }); + break; + } + } + + return result; +}); diff --git a/react/features/talk-while-muted/reducer.js b/react/features/talk-while-muted/reducer.js new file mode 100644 index 000000000..27e532538 --- /dev/null +++ b/react/features/talk-while-muted/reducer.js @@ -0,0 +1,17 @@ +// @flow + +import { ReducerRegistry, set } from '../base/redux'; + +import { SET_CURRENT_NOTIFICATION_UID } from './actionTypes'; + +/** + * Reduces the redux actions of the feature talk while muted. + */ +ReducerRegistry.register('features/talk-while-muted', (state = { }, action) => { + switch (action.type) { + case SET_CURRENT_NOTIFICATION_UID: + return set(state, 'currentNotificationUid', action.uid); + } + + return state; +}); diff --git a/react/features/talk-while-muted/sounds.js b/react/features/talk-while-muted/sounds.js new file mode 100644 index 000000000..e28f610af --- /dev/null +++ b/react/features/talk-while-muted/sounds.js @@ -0,0 +1,6 @@ +/** + * The file used for the talk while muted sound notification. + * + * @type {string} + */ +export const TALK_WHILE_MUTED_SOUND_FILE = 'talkWhileMuted.mp3'; diff --git a/sounds/talkWhileMuted.mp3 b/sounds/talkWhileMuted.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..cf07fb704cdd0afefe7f87e4f4c7917dd9cdc674 GIT binary patch literal 9613 zcmeI$*H;tTmk00=kS-HD_(j>>5x#Qgcgc)DWddV zq)JslM4AYK^?GHlzghDa%skG1I1gv7a~{rTuf4wOT>PCr2mo?Nef>_)KQ%u1qGb7; z6vol}lX27bsu3gm7(T7pYqLdiTbver(bSpRWrm+;tZHwgTj2 z3%mBiP3*#>8%7HYLw?&>L9QtHd%WHH{?D(*ZtR-|F~VZYM)@Mrja=*n1C z(eXGq3cycLy8pN#ZsXIb5F;iu0UUq(H)JfUj4?Pg!UGY-_|}J$e<@T0`4!yT9P*HL z0<0ay3M)__1;V+jBWVkVO{J3(N<1#*?|?RgjkXTm0GmRSrHt z>gJJI*5v7(cQ^QD{alt(AytZ@q2hsRTy?x`WUI&%@mKx-NJw&eY|HuZ8&wF#i-z$K zh*lh&6~Z1E4mp-{N8T^BKhL)%t0Yqya5v(D|9${3I!f- zOs6r#W_UC62s38{rZc8HC#j1oJ@un>gu`NET%pl@30Y}kuq^FlNzNYgxpiz7I|Mpl z5Y+smyT7EOEKk{cFcS$$N~@qO*)f>+Y@4~^{IAo4|xB~jZ%cwg=ZwoQrZ@-N5RU9|WToqaAH*B9Q0`8Ud)6czW zKf=wXLSkaRrvj*4f8o2O zL%afW>dnu2j7bLmCOgmh^i$>FE|uBuWbV9UK5}Xk^wrcC?W(iV3?L+SCV%^9Xxni! zq~{AC1IiKSMnd|H?q=y#_#b#eP-SD4)*%-!CrUn?ouyXzr;9kcY;_1m6pVd-kPmPU z6*O9<#|iyV#|m*px^sF6cnH(;iAH4(cEifRyK$J_DZn2g`AG0*cAL)eXd$(B_XZ6rN2)1VFvCxfDJpT;(Zyf=GJP+S85sF;clXd}gD0sG5VKVS z@Z-1ybg6c@^843T$uN_4A^-qpc>o&Co+&SVn@v#cvUgNNsrzUI0Q;omEQg2$>)&-P$WWcjR;q;7D{!c1k1vc`dzE{o8Ix}XfZB3dNA z#qY_e@9T}57A@oC#h)2HGnkVytZ&9fbuK3@qioZtaOpZ%Xb58hZ)~3~$uLBCiA+>^ z`{Z1;);jA;Kr;NwQ1z_^S)b2SvM(l%j@>PPtc~xINqe`yid1wxks>7xJ3Qx&%4z&f zC{j1SALLAsdGK-d^+R`Rp-vZ{mS59Ht?PDEUh-42yDj(5eksem{q^*b zdwlpCAug8dH`q_u{F_VM$?=}%qAfL zj6bx%;#;w6(#lMCU;x%zNL<^)mF_4Yi>hK}G)=x^Kv#RfL+P3M`DSi&yzc7c%P$uz zKMg@sRUAk&M@7e)@YR32z4vp+%R2}DM5Wx+w~c!neE)78j7XM;Z2c24X1`omFII!t z|E_#-`|pb-t0(x4RE^>@-w9!1FgLVoyx}#;aPRlXO95-&v%fAbHvYPC((QZOl11pH z^h?9%zN>CBbQQ+k)SqKf>40Hlr6{Y#Jl(4Dd_v{GJ>D-lVIDh=Uads-I!4OU)6%l^ zP9$-tVuabInrKtI0I!@K0i01Obem2k>P5g;F_q$`dB&a=8M=4auFeLURzFXk0SC?7 z=>^WfQ8*3qteVzp_$&%rZ-@$SXcZuWqXj2#yQ4fqyf-BH%r>|)jdNRbsgm6ix+Dg> z;!N2tcT=26W_k}*SHddgYB5Ur@23$uxYZn6_4oIEKKZ#cxlaxepLQqvnlXG!@9a~E z=`INB>^N#3>bxV7IZ3QgdSN_KQBFfINQ3<�j)TGXUi%izyO)j@BcTj*$;=|8^2t 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 literal 0 HcmV?d00001 diff --git a/webpack.config.js b/webpack.config.js index 3ae4af15f..d8f56f90c 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -186,6 +186,7 @@ module.exports = [ function devServerProxyBypass({ path }) { if (path.startsWith('/css/') || path.startsWith('/doc/') || path.startsWith('/fonts/') || path.startsWith('/images/') + || path.startsWith('/sounds/') || path.startsWith('/static/')) { return path; }