+ {
+ e.stopPropagation();
+ micEnabled ? onMuteMic(peer.name) : onUnmuteMic(peer.name);
+ }}
+ />
+
+
+ {
+ e.stopPropagation();
+ videoVisible ?
+ onDisableWebcam(peer.name) : onEnableWebcam(peer.name);
+ }}
+ />
{videoVisible && !webcamConsumer.supported ?
@@ -83,10 +104,14 @@ const Peer = (props) =>
Peer.propTypes =
{
- peer : appPropTypes.Peer.isRequired,
- micConsumer : appPropTypes.Consumer,
- webcamConsumer : appPropTypes.Consumer,
- screenConsumer : appPropTypes.Consumer
+ peer : appPropTypes.Peer.isRequired,
+ micConsumer : appPropTypes.Consumer,
+ webcamConsumer : appPropTypes.Consumer,
+ screenConsumer : appPropTypes.Consumer,
+ onMuteMic : PropTypes.func.isRequired,
+ onUnmuteMic : PropTypes.func.isRequired,
+ onEnableWebcam : PropTypes.func.isRequired,
+ onDisableWebcam : PropTypes.func.isRequired
};
const mapStateToProps = (state, { name }) =>
@@ -109,6 +134,32 @@ const mapStateToProps = (state, { name }) =>
};
};
-const PeerContainer = connect(mapStateToProps)(Peer);
+const mapDispatchToProps = (dispatch) =>
+{
+ return {
+ onMuteMic : (peerName) =>
+ {
+ dispatch(requestActions.mutePeerAudio(peerName));
+ },
+ onUnmuteMic : (peerName) =>
+ {
+ dispatch(requestActions.unmutePeerAudio(peerName));
+ },
+ onEnableWebcam : (peerName) =>
+ {
+
+ dispatch(requestActions.resumePeerVideo(peerName));
+ },
+ onDisableWebcam : (peerName) =>
+ {
+ dispatch(requestActions.pausePeerVideo(peerName));
+ }
+ };
+};
+
+const PeerContainer = connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(Peer);
export default PeerContainer;
diff --git a/app/lib/components/PeerView.jsx b/app/lib/components/PeerView.jsx
index e4f4572..cda3d47 100644
--- a/app/lib/components/PeerView.jsx
+++ b/app/lib/components/PeerView.jsx
@@ -315,7 +315,7 @@ PeerView.propTypes =
screenTrack : PropTypes.any,
videoVisible : PropTypes.bool.isRequired,
videoProfile : PropTypes.string,
- screenVisible : PropTypes.bool.isRequired,
+ screenVisible : PropTypes.bool,
screenProfile : PropTypes.string,
audioCodec : PropTypes.string,
videoCodec : PropTypes.string,
diff --git a/app/lib/components/Peers.jsx b/app/lib/components/Peers.jsx
index abb8d62..39dd406 100644
--- a/app/lib/components/Peers.jsx
+++ b/app/lib/components/Peers.jsx
@@ -16,9 +16,10 @@ class Peers extends React.Component
ratio : 1.334
};
}
- updateDimensions()
+
+ updateDimensions(nextProps = null)
{
- const n = this.props.peers.length;
+ const n = nextProps ? nextProps.peers.length : this.props.peers.length;
if (n == 0)
{
@@ -62,6 +63,11 @@ class Peers extends React.Component
window.removeEventListener('resize', this.updateDimensions.bind(this));
}
+ componentWillReceiveProps(nextProps)
+ {
+ this.updateDimensions(nextProps);
+ }
+
render()
{
const {
@@ -77,8 +83,6 @@ class Peers extends React.Component
'height' : peerHeight
};
- this.updateDimensions();
-
return (
{
diff --git a/app/lib/redux/reducers/peers.js b/app/lib/redux/reducers/peers.js
index 8ff36bd..b7001b9 100644
--- a/app/lib/redux/reducers/peers.js
+++ b/app/lib/redux/reducers/peers.js
@@ -34,6 +34,32 @@ const peers = (state = initialState, action) =>
return { ...state, [newPeer.name]: newPeer };
}
+ case 'SET_PEER_VIDEO_IN_PROGRESS':
+ {
+ const { peerName, flag } = action.payload;
+ const peer = state[peerName];
+
+ if (!peer)
+ throw new Error('no Peer found');
+
+ const newPeer = { ...peer, peerVideoInProgress: flag };
+
+ return { ...state, [newPeer.name]: newPeer };
+ }
+
+ case 'SET_PEER_AUDIO_IN_PROGRESS':
+ {
+ const { peerName, flag } = action.payload;
+ const peer = state[peerName];
+
+ if (!peer)
+ throw new Error('no Peer found');
+
+ const newPeer = { ...peer, peerAudioInProgress: flag };
+
+ return { ...state, [newPeer.name]: newPeer };
+ }
+
case 'SET_PEER_RAISE_HAND_STATE':
{
const { peerName, raiseHandState } = action.payload;
diff --git a/app/lib/redux/requestActions.js b/app/lib/redux/requestActions.js
index e13203b..f8d2178 100644
--- a/app/lib/redux/requestActions.js
+++ b/app/lib/redux/requestActions.js
@@ -78,6 +78,38 @@ export const disableAudioOnly = () =>
};
};
+export const mutePeerAudio = (peerName) =>
+{
+ return {
+ type : 'MUTE_PEER_AUDIO',
+ payload : { peerName }
+ };
+};
+
+export const unmutePeerAudio = (peerName) =>
+{
+ return {
+ type : 'UNMUTE_PEER_AUDIO',
+ payload : { peerName }
+ };
+};
+
+export const pausePeerVideo = (peerName) =>
+{
+ return {
+ type : 'PAUSE_PEER_VIDEO',
+ payload : { peerName }
+ };
+};
+
+export const resumePeerVideo = (peerName) =>
+{
+ return {
+ type : 'RESUME_PEER_VIDEO',
+ payload : { peerName }
+ };
+};
+
export const raiseHand = () =>
{
return {
diff --git a/app/lib/redux/roomClientMiddleware.js b/app/lib/redux/roomClientMiddleware.js
index 971985a..628cba3 100644
--- a/app/lib/redux/roomClientMiddleware.js
+++ b/app/lib/redux/roomClientMiddleware.js
@@ -102,6 +102,42 @@ export default ({ dispatch, getState }) => (next) =>
break;
}
+ case 'MUTE_PEER_AUDIO':
+ {
+ const { peerName } = action.payload;
+
+ client.mutePeerAudio(peerName);
+
+ break;
+ }
+
+ case 'UNMUTE_PEER_AUDIO':
+ {
+ const { peerName } = action.payload;
+
+ client.unmutePeerAudio(peerName);
+
+ break;
+ }
+
+ case 'PAUSE_PEER_VIDEO':
+ {
+ const { peerName } = action.payload;
+
+ client.pausePeerVideo(peerName);
+
+ break;
+ }
+
+ case 'RESUME_PEER_VIDEO':
+ {
+ const { peerName } = action.payload;
+
+ client.resumePeerVideo(peerName);
+
+ break;
+ }
+
case 'RAISE_HAND':
{
client.sendRaiseHandState(true);
diff --git a/app/lib/redux/stateActions.js b/app/lib/redux/stateActions.js
index 21bb7c3..4c6b61d 100644
--- a/app/lib/redux/stateActions.js
+++ b/app/lib/redux/stateActions.js
@@ -86,6 +86,22 @@ export const setAudioOnlyInProgress = (flag) =>
};
};
+export const setPeerVideoInProgress = (peerName, flag) =>
+{
+ return {
+ type : 'SET_PEER_VIDEO_IN_PROGRESS',
+ payload : { peerName, flag }
+ };
+};
+
+export const setPeerAudioInProgress = (peerName, flag) =>
+{
+ return {
+ type : 'SET_PEER_AUDIO_IN_PROGRESS',
+ payload : { peerName, flag }
+ };
+};
+
export const setMyRaiseHandState = (flag) =>
{
return {
diff --git a/app/stylus/components/Peer.styl b/app/stylus/components/Peer.styl
index 3c32d99..daa2baa 100644
--- a/app/stylus/components/Peer.styl
+++ b/app/stylus/components/Peer.styl
@@ -4,6 +4,87 @@
height: 100%;
width: 100%;
+ > .controls {
+ position: absolute;
+ z-index: 10;
+ right: 0;
+ top: 0;
+ display: flex;
+ flex-direction:; row;
+ justify-content: flex-start;
+ align-items: center;
+
+ > .button {
+ flex: 0 0 auto;
+ margin: 4px;
+ border-radius: 2px;
+ background-position: center;
+ background-size: 75%;
+ background-repeat: no-repeat;
+ background-color: rgba(#000, 0.5);
+ cursor: pointer;
+ transition-property: opacity, background-color;
+ transition-duration: 0.15s;
+
+ +desktop() {
+ width: 24px;
+ height: 24px;
+ opacity: 0.85;
+
+ &:hover {
+ opacity: 1;
+ }
+ }
+
+ +mobile() {
+ width: 22px;
+ height: 22px;
+ }
+
+ &.unsupported {
+ pointer-events: none;
+ }
+
+ &.disabled {
+ pointer-events: none;
+ opacity: 0.5;
+ }
+
+ &.on {
+ background-color: rgba(#fff, 0.7);
+ }
+
+ &.mic {
+ &.on {
+ background-image: url('/resources/images/icon_mic_black_on.svg');
+ }
+
+ &.off {
+ background-image: url('/resources/images/icon_mic_white_off.svg');
+ background-color: rgba(#d42241, 0.7);
+ }
+
+ &.unsupported {
+ background-image: url('/resources/images/icon_mic_white_unsupported.svg');
+ }
+ }
+
+ &.webcam {
+ &.on {
+ background-image: url('/resources/images/icon_webcam_black_on.svg');
+ }
+
+ &.off {
+ background-image: url('/resources/images/icon_webcam_white_on.svg');
+ }
+
+ &.unsupported {
+ background-image: url('/resources/images/icon_webcam_white_unsupported.svg');
+ }
+ }
+ }
+ }
+
+mobile() {
display: flex;
flex-direction: column;
@@ -11,47 +92,6 @@
align-items: center;
}
- > .indicators {
- position: absolute;
- z-index: 10
- top: 0;
- left: 0;
- right: 0;
- display: flex;
- flex-direction:; row;
- justify-content: flex-end;
- align-items: center;
-
- > .icon {
- flex: 0 0 auto;
- margin: 4px;
- margin-left: 0;
- width: 32px;
- height: 32px;
- background-position: center;
- background-size: 75%;
- background-repeat: no-repeat;
- transition-property: opacity;
- transition-duration: 0.15s;
-
- +desktop() {
- opacity: 0.85;
- }
-
- &.raise-hand {
- background-image: url('/resources/images/icon_remote_raise_hand.svg');
- }
-
- &.mic-off {
- background-image: url('/resources/images/icon_remote_mic_white_off.svg');
- }
-
- &.webcam-off {
- background-image: url('/resources/images/icon_remote_webcam_white_off.svg');
- }
- }
- }
-
.incompatible-video {
position: absolute;
z-index: 2