add audio logs (join/leave/mute/unmute) / fix lint issues
This commit is contained in:
parent
fd7a5918c1
commit
4fba9978d3
@ -4,6 +4,7 @@ import { withModalMounter } from '/imports/ui/components/modal/service';
|
||||
import AudioManager from '/imports/ui/services/audio-manager';
|
||||
import { makeCall } from '/imports/ui/services/api';
|
||||
import lockContextContainer from '/imports/ui/components/lock-viewers/context/container';
|
||||
import logger from '/imports/startup/client/logger';
|
||||
import AudioControls from './component';
|
||||
import AudioModalContainer from '../audio-modal/container';
|
||||
import Service from '../service';
|
||||
@ -32,16 +33,37 @@ const processToggleMuteFromOutside = (e) => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleLeaveAudio = () => {
|
||||
Service.exitAudio();
|
||||
logger.info({
|
||||
logCode: 'audiocontrols_leave_audio',
|
||||
extraInfo: { logType: 'user_action' },
|
||||
}, 'audio connection closed by user');
|
||||
};
|
||||
|
||||
const {
|
||||
currentUser,
|
||||
isConnected,
|
||||
isListenOnly,
|
||||
isEchoTest,
|
||||
isMuted,
|
||||
isConnecting,
|
||||
isHangingUp,
|
||||
isTalking,
|
||||
toggleMuteMicrophone,
|
||||
joinListenOnly,
|
||||
} = Service;
|
||||
|
||||
export default lockContextContainer(withModalMounter(withTracker(({ mountModal, userLocks }) => ({
|
||||
processToggleMuteFromOutside: arg => processToggleMuteFromOutside(arg),
|
||||
showMute: Service.isConnected() && !Service.isListenOnly() && !Service.isEchoTest() && !userLocks.userMic,
|
||||
muted: Service.isConnected() && !Service.isListenOnly() && Service.isMuted(),
|
||||
inAudio: Service.isConnected() && !Service.isEchoTest(),
|
||||
listenOnly: Service.isConnected() && Service.isListenOnly(),
|
||||
disable: Service.isConnecting() || Service.isHangingUp() || !Meteor.status().connected,
|
||||
talking: Service.isTalking() && !Service.isMuted(),
|
||||
currentUser: Service.currentUser(),
|
||||
handleToggleMuteMicrophone: () => Service.toggleMuteMicrophone(),
|
||||
handleJoinAudio: () => (Service.isConnected() ? Service.joinListenOnly() : mountModal(<AudioModalContainer />)),
|
||||
handleLeaveAudio: () => Service.exitAudio(),
|
||||
showMute: isConnected() && !isListenOnly() && !isEchoTest() && !userLocks.userMic,
|
||||
muted: isConnected() && !isListenOnly() && isMuted(),
|
||||
inAudio: isConnected() && !isEchoTest(),
|
||||
listenOnly: isConnected() && isListenOnly(),
|
||||
disable: isConnecting() || isHangingUp() || !Meteor.status().connected,
|
||||
talking: isTalking() && !isMuted(),
|
||||
currentUser: currentUser(),
|
||||
handleToggleMuteMicrophone: () => toggleMuteMicrophone(),
|
||||
handleJoinAudio: () => (isConnected() ? joinListenOnly() : mountModal(<AudioModalContainer />)),
|
||||
handleLeaveAudio,
|
||||
}))(AudioControlsContainer)));
|
||||
|
@ -3,6 +3,9 @@ import Auth from '/imports/ui/services/auth';
|
||||
import AudioManager from '/imports/ui/services/audio-manager';
|
||||
import Meetings from '/imports/api/meetings';
|
||||
import mapUser from '/imports/ui/services/user/mapUser';
|
||||
import { makeCall } from '/imports/ui/services/api';
|
||||
import VoiceUsers from '/imports/api/voice-users';
|
||||
import logger from '/imports/startup/client/logger';
|
||||
|
||||
const ROLE_MODERATOR = Meteor.settings.public.user.role_moderator;
|
||||
|
||||
@ -34,6 +37,24 @@ const init = (messages, intl) => {
|
||||
|
||||
const currentUser = () => mapUser(Users.findOne({ intId: Auth.userID }));
|
||||
|
||||
const toggleMuteMicrophone = () => {
|
||||
makeCall('toggleSelfVoice');
|
||||
const cvu = VoiceUsers.findOne({ meetingId: Auth.meetingID, intId: Auth.userID });
|
||||
if (cvu) {
|
||||
if (cvu.muted) {
|
||||
logger.info({
|
||||
logCode: 'audiomanager_unmute_audio',
|
||||
extraInfo: { logType: 'user_action' },
|
||||
}, 'microphone unmuted by user');
|
||||
} else {
|
||||
logger.info({
|
||||
logCode: 'audiomanager_mute_audio',
|
||||
extraInfo: { logType: 'user_action' },
|
||||
}, 'microphone muted by user');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
init,
|
||||
exitAudio: () => AudioManager.exitAudio(),
|
||||
@ -41,7 +62,7 @@ export default {
|
||||
joinListenOnly: () => AudioManager.joinListenOnly(),
|
||||
joinMicrophone: () => AudioManager.joinMicrophone(),
|
||||
joinEchoTest: () => AudioManager.joinEchoTest(),
|
||||
toggleMuteMicrophone: () => AudioManager.toggleMuteMicrophone(),
|
||||
toggleMuteMicrophone,
|
||||
changeInputDevice: inputDeviceId => AudioManager.changeInputDevice(inputDeviceId),
|
||||
changeOutputDevice: outputDeviceId => AudioManager.changeOutputDevice(outputDeviceId),
|
||||
isConnected: () => AudioManager.isConnected,
|
||||
|
@ -1,7 +1,9 @@
|
||||
import React, { Component } from 'react';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { defineMessages, injectIntl, intlShape } from 'react-intl';
|
||||
import { withModalMounter } from '/imports/ui/components/modal/service';
|
||||
import Modal from '/imports/ui/components/modal/fullscreen/component';
|
||||
import logger from '/imports/startup/client/logger';
|
||||
import PropTypes from 'prop-types';
|
||||
import AudioService from '../audio/service';
|
||||
import VideoService from '../video-provider/service';
|
||||
import { styles } from './styles';
|
||||
@ -37,6 +39,19 @@ const intlMessages = defineMessages({
|
||||
},
|
||||
});
|
||||
|
||||
const propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
breakout: PropTypes.objectOf(Object).isRequired,
|
||||
getURL: PropTypes.func.isRequired,
|
||||
mountModal: PropTypes.func.isRequired,
|
||||
breakoutURL: PropTypes.string.isRequired,
|
||||
isFreeJoin: PropTypes.bool.isRequired,
|
||||
currentVoiceUser: PropTypes.objectOf(Object).isRequired,
|
||||
requestJoinURL: PropTypes.func.isRequired,
|
||||
breakouts: PropTypes.arrayOf(Object).isRequired,
|
||||
breakoutName: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
class BreakoutJoinConfirmation extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@ -56,10 +71,21 @@ class BreakoutJoinConfirmation extends Component {
|
||||
mountModal,
|
||||
breakoutURL,
|
||||
isFreeJoin,
|
||||
currentVoiceUser,
|
||||
} = this.props;
|
||||
const url = isFreeJoin ? getURL(this.state.selectValue) : breakoutURL;
|
||||
// leave main room's audio when joining a breakout room
|
||||
AudioService.exitAudio();
|
||||
|
||||
const { selectValue } = this.state;
|
||||
const url = isFreeJoin ? getURL(selectValue) : breakoutURL;
|
||||
|
||||
if (currentVoiceUser && currentVoiceUser.joined) {
|
||||
// leave main room's audio when joining a breakout room
|
||||
AudioService.exitAudio();
|
||||
logger.info({
|
||||
logCode: 'breakoutjoinconfirmation_ended_audio',
|
||||
extraInfo: { logType: 'user_action' },
|
||||
}, 'joining breakout room closed audio in the main room');
|
||||
}
|
||||
|
||||
VideoService.exitVideo();
|
||||
window.open(url);
|
||||
mountModal(null);
|
||||
@ -67,21 +93,32 @@ class BreakoutJoinConfirmation extends Component {
|
||||
|
||||
handleSelectChange(e) {
|
||||
const { value } = e.target;
|
||||
const { requestJoinURL } = this.props;
|
||||
this.setState({ selectValue: value });
|
||||
this.props.requestJoinURL(value);
|
||||
requestJoinURL(value);
|
||||
}
|
||||
|
||||
renderSelectMeeting() {
|
||||
const { breakouts, intl } = this.props;
|
||||
const { selectValue } = this.state;
|
||||
return (
|
||||
<div className={styles.selectParent}>
|
||||
{`${intl.formatMessage(intlMessages.freeJoinMessage)}`}
|
||||
<select
|
||||
className={styles.select}
|
||||
value={this.state.selectValue}
|
||||
value={selectValue}
|
||||
onChange={this.handleSelectChange}
|
||||
>
|
||||
{breakouts.map(({ name, breakoutId }) => (<option key={breakoutId} value={breakoutId}>{name}</option>))}
|
||||
{
|
||||
breakouts.map(({ name, breakoutId }) => (
|
||||
<option
|
||||
key={breakoutId}
|
||||
value={breakoutId}
|
||||
>
|
||||
{name}
|
||||
</option>
|
||||
))
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
);
|
||||
@ -89,6 +126,7 @@ class BreakoutJoinConfirmation extends Component {
|
||||
|
||||
render() {
|
||||
const { intl, breakoutName, isFreeJoin } = this.props;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={intl.formatMessage(intlMessages.title)}
|
||||
@ -110,3 +148,5 @@ class BreakoutJoinConfirmation extends Component {
|
||||
}
|
||||
|
||||
export default withModalMounter(injectIntl(BreakoutJoinConfirmation));
|
||||
|
||||
BreakoutJoinConfirmation.propTypes = propTypes;
|
||||
|
@ -2,12 +2,16 @@ import React from 'react';
|
||||
import { withTracker } from 'meteor/react-meteor-data';
|
||||
import Breakouts from '/imports/api/breakouts';
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
import VoiceUsers from '/imports/api/voice-users/';
|
||||
import { makeCall } from '/imports/ui/services/api';
|
||||
import breakoutService from '/imports/ui/components/breakout-room/service';
|
||||
import BreakoutJoinConfirmationComponent from './component';
|
||||
|
||||
const BreakoutJoinConfirmationContrainer = props =>
|
||||
(<BreakoutJoinConfirmationComponent {...props} />);
|
||||
const BreakoutJoinConfirmationContrainer = props => (
|
||||
<BreakoutJoinConfirmationComponent
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
const getURL = (breakoutId) => {
|
||||
const currentUserId = Auth.userID;
|
||||
@ -31,6 +35,8 @@ export default withTracker(({ breakout, mountModal, breakoutName }) => {
|
||||
requestJoinURL(breakoutId);
|
||||
}
|
||||
|
||||
const currentVoiceUser = VoiceUsers.findOne({ meetingId: Auth.meetingID, intId: Auth.userID });
|
||||
|
||||
return {
|
||||
isFreeJoin,
|
||||
mountModal,
|
||||
@ -39,5 +45,6 @@ export default withTracker(({ breakout, mountModal, breakoutName }) => {
|
||||
breakouts: breakoutService.getBreakouts(),
|
||||
requestJoinURL,
|
||||
getURL,
|
||||
currentVoiceUser,
|
||||
};
|
||||
})(BreakoutJoinConfirmationContrainer);
|
||||
|
@ -11,6 +11,8 @@ import { EMOJI_STATUSES } from '/imports/utils/statuses';
|
||||
import { makeCall } from '/imports/ui/services/api';
|
||||
import _ from 'lodash';
|
||||
import KEY_CODES from '/imports/utils/keyCodes';
|
||||
import AudioService from '/imports/ui/components/audio/service';
|
||||
import logger from '/imports/startup/client/logger';
|
||||
|
||||
const CHAT_CONFIG = Meteor.settings.public.chat;
|
||||
const PUBLIC_GROUP_CHAT_ID = CHAT_CONFIG.public_group_id;
|
||||
@ -382,9 +384,13 @@ const removeUser = (userId) => {
|
||||
|
||||
const toggleVoice = (userId) => {
|
||||
if (userId === Auth.userID) {
|
||||
makeCall('toggleSelfVoice');
|
||||
AudioService.toggleMuteMicrophone();
|
||||
} else {
|
||||
makeCall('toggleVoice', userId);
|
||||
logger.info({
|
||||
logCode: 'usermenu_option_mute_audio',
|
||||
extraInfo: { logType: 'moderator_action' },
|
||||
}, 'moderator muted user microphone');
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
import Service from '/imports/ui/components/actions-bar/service';
|
||||
import userListService from '/imports/ui/components/user-list/service';
|
||||
import logger from '/imports/startup/client/logger';
|
||||
import { defineMessages, injectIntl, intlShape } from 'react-intl';
|
||||
import { notify } from '/imports/ui/services/notification';
|
||||
import UserOptions from './component';
|
||||
@ -43,9 +44,38 @@ const UserOptionsContainer = withTracker((props) => {
|
||||
);
|
||||
};
|
||||
|
||||
const isMeetingMuteOnStart = () => {
|
||||
const { voiceProp } = meeting;
|
||||
const { muteOnStart } = voiceProp;
|
||||
return muteOnStart;
|
||||
};
|
||||
|
||||
const meetingMuteDisabledLog = () => logger.info({
|
||||
logCode: 'useroptions_unmute_all',
|
||||
extraInfo: { logType: 'moderator_action' },
|
||||
}, 'moderator disabled meeting mute');
|
||||
|
||||
return {
|
||||
toggleMuteAllUsers: () => muteAllUsers(Auth.userID),
|
||||
toggleMuteAllUsersExceptPresenter: () => muteAllExceptPresenter(Auth.userID),
|
||||
toggleMuteAllUsers: () => {
|
||||
muteAllUsers(Auth.userID);
|
||||
if (isMeetingMuteOnStart()) {
|
||||
return meetingMuteDisabledLog();
|
||||
}
|
||||
return logger.info({
|
||||
logCode: 'useroptions_mute_all',
|
||||
extraInfo: { logType: 'moderator_action' },
|
||||
}, 'moderator enabled meeting mute, all users muted');
|
||||
},
|
||||
toggleMuteAllUsersExceptPresenter: () => {
|
||||
muteAllExceptPresenter(Auth.userID);
|
||||
if (isMeetingMuteOnStart()) {
|
||||
return meetingMuteDisabledLog();
|
||||
}
|
||||
return logger.info({
|
||||
logCode: 'useroptions_mute_all_except_presenter',
|
||||
extraInfo: { logType: 'moderator_action' },
|
||||
}, 'moderator enabled meeting mute, all users muted except presenter');
|
||||
},
|
||||
toggleStatus,
|
||||
isMeetingMuted: meeting.voiceProp.muteOnStart,
|
||||
isUserPresenter: Service.isUserPresenter(),
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { Tracker } from 'meteor/tracker';
|
||||
import { makeCall } from '/imports/ui/services/api';
|
||||
import KurentoBridge from '/imports/api/audio/client/bridge/kurento';
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
import VoiceUsers from '/imports/api/voice-users';
|
||||
@ -138,11 +137,13 @@ class AudioManager {
|
||||
extension: ECHO_TEST_NUMBER,
|
||||
inputStream: this.inputStream,
|
||||
};
|
||||
logger.info({ logCode: 'audiomanager_join_echotest', extraInfo: { logType: 'user_action' } }, 'User requested to join audio conference with mic');
|
||||
return this.bridge.joinAudio(callOptions, this.callStateCallback.bind(this));
|
||||
});
|
||||
}
|
||||
|
||||
async joinListenOnly(retries = 0) {
|
||||
async joinListenOnly(r = 0) {
|
||||
let retries = r;
|
||||
this.isListenOnly = true;
|
||||
this.isEchoTest = false;
|
||||
|
||||
@ -180,6 +181,11 @@ class AudioManager {
|
||||
});
|
||||
|
||||
const handleListenOnlyError = async (err) => {
|
||||
const error = {
|
||||
type: 'MEDIA_ERROR',
|
||||
message: this.messages.error.MEDIA_ERROR,
|
||||
};
|
||||
|
||||
if (iceGatheringTimeout) {
|
||||
clearTimeout(iceGatheringTimeout);
|
||||
}
|
||||
@ -191,12 +197,12 @@ class AudioManager {
|
||||
retries,
|
||||
},
|
||||
}, 'Listen only error');
|
||||
throw {
|
||||
type: 'MEDIA_ERROR',
|
||||
message: this.messages.error.MEDIA_ERROR,
|
||||
};
|
||||
|
||||
throw error;
|
||||
};
|
||||
|
||||
logger.info({ logCode: 'audiomanager_join_listenonly', extraInfo: { logType: 'user_action' } }, 'user requested to connect to audio conference as listen only');
|
||||
|
||||
return this.onAudioJoining()
|
||||
.then(() => Promise.race([
|
||||
bridge.joinAudio(callOptions, this.callStateCallback.bind(this)),
|
||||
@ -214,13 +220,16 @@ class AudioManager {
|
||||
}
|
||||
|
||||
try {
|
||||
await this.joinListenOnly(++retries);
|
||||
retries += 1;
|
||||
await this.joinListenOnly(retries);
|
||||
} catch (error) {
|
||||
return handleListenOnlyError(error);
|
||||
}
|
||||
} else {
|
||||
handleListenOnlyError(err);
|
||||
return handleListenOnlyError(err);
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@ -247,10 +256,6 @@ class AudioManager {
|
||||
return this.bridge.transferCall(this.onAudioJoin.bind(this));
|
||||
}
|
||||
|
||||
toggleMuteMicrophone() {
|
||||
makeCall('toggleSelfVoice');
|
||||
}
|
||||
|
||||
onAudioJoin() {
|
||||
this.isConnecting = false;
|
||||
this.isConnected = true;
|
||||
@ -362,9 +367,11 @@ class AudioManager {
|
||||
this.listenOnlyAudioContext.close();
|
||||
}
|
||||
|
||||
this.listenOnlyAudioContext = window.AudioContext
|
||||
? new window.AudioContext()
|
||||
: new window.webkitAudioContext();
|
||||
const { AudioContext, WebkitAudioContext } = window;
|
||||
|
||||
this.listenOnlyAudioContext = AudioContext
|
||||
? new AudioContext()
|
||||
: new WebkitAudioContext();
|
||||
|
||||
const dest = this.listenOnlyAudioContext.createMediaStreamDestination();
|
||||
|
||||
@ -402,9 +409,11 @@ class AudioManager {
|
||||
return Promise.resolve(inputDevice);
|
||||
};
|
||||
|
||||
const handleChangeInputDeviceError = () => Promise.reject({
|
||||
type: 'MEDIA_ERROR',
|
||||
message: this.messages.error.MEDIA_ERROR,
|
||||
const handleChangeInputDeviceError = () => new Promise((reject) => {
|
||||
reject({
|
||||
type: 'MEDIA_ERROR',
|
||||
message: this.messages.error.MEDIA_ERROR,
|
||||
});
|
||||
});
|
||||
|
||||
if (!deviceId) {
|
||||
|
Loading…
Reference in New Issue
Block a user