watch for voice call state updates instead of DTMFs in the client
This commit is contained in:
parent
4b5c6c65e9
commit
6a4ba7a300
@ -10,6 +10,10 @@ import {
|
|||||||
analyzeSdp,
|
analyzeSdp,
|
||||||
logSelectedCandidate,
|
logSelectedCandidate,
|
||||||
} from '/imports/utils/sdpUtils';
|
} from '/imports/utils/sdpUtils';
|
||||||
|
import { Tracker } from 'meteor/tracker';
|
||||||
|
import VoiceCallStates from '/imports/api/voice-call-states';
|
||||||
|
import CallStateOptions from '/imports/api/voice-call-states/utils/callStates';
|
||||||
|
import Auth from '/imports/ui/services/auth';
|
||||||
|
|
||||||
const MEDIA = Meteor.settings.public.media;
|
const MEDIA = Meteor.settings.public.media;
|
||||||
const MEDIA_TAG = MEDIA.mediaTag;
|
const MEDIA_TAG = MEDIA.mediaTag;
|
||||||
@ -47,14 +51,6 @@ class SIPSession {
|
|||||||
this.reconnectAttempt = reconnectAttempt;
|
this.reconnectAttempt = reconnectAttempt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static parseDTMF(message) {
|
|
||||||
const parse = message.match(/Signal=(.)/);
|
|
||||||
if (parse && parse.length === 2) {
|
|
||||||
return parse[1];
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
joinAudio({ isListenOnly, extension, inputStream }, managerCallback) {
|
joinAudio({ isListenOnly, extension, inputStream }, managerCallback) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const callExtension = extension ? `${extension}${this.userData.voiceBridge}` : this.userData.voiceBridge;
|
const callExtension = extension ? `${extension}${this.userData.voiceBridge}` : this.userData.voiceBridge;
|
||||||
@ -119,8 +115,10 @@ class SIPSession {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.inEchoTest = false;
|
this.inEchoTest = false;
|
||||||
|
|
||||||
const timeout = setInterval(() => {
|
let trackerControl = null;
|
||||||
clearInterval(timeout);
|
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
trackerControl.stop();
|
||||||
logger.error({ logCode: 'sip_js_transfer_timed_out' }, 'Timeout on transferring from echo test to conference');
|
logger.error({ logCode: 'sip_js_transfer_timed_out' }, 'Timeout on transferring from echo test to conference');
|
||||||
this.callback({
|
this.callback({
|
||||||
status: this.baseCallStates.failed,
|
status: this.baseCallStates.failed,
|
||||||
@ -136,15 +134,22 @@ class SIPSession {
|
|||||||
// This is is the call transfer code ask @chadpilkey
|
// This is is the call transfer code ask @chadpilkey
|
||||||
this.currentSession.dtmf(1);
|
this.currentSession.dtmf(1);
|
||||||
|
|
||||||
this.currentSession.on('dtmf', (event) => {
|
Tracker.autorun((c) => {
|
||||||
if (event.body && (typeof event.body === 'string')) {
|
trackerControl = c;
|
||||||
const key = SIPSession.parseDTMF(event.body);
|
const selector = { meetingId: Auth.meetingID, userId: Auth.userID };
|
||||||
if (key === '7') {
|
const query = VoiceCallStates.find(selector);
|
||||||
clearInterval(timeout);
|
|
||||||
onTransferSuccess();
|
query.observeChanges({
|
||||||
resolve();
|
changed: (id, fields) => {
|
||||||
}
|
if (fields.callState === CallStateOptions.IN_CONFERENCE) {
|
||||||
}
|
clearTimeout(timeout);
|
||||||
|
onTransferSuccess();
|
||||||
|
|
||||||
|
c.stop();
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -491,17 +496,21 @@ class SIPSession {
|
|||||||
};
|
};
|
||||||
['iceConnectionClosed'].forEach(e => mediaHandler.on(e, handleIceConnectionTerminated));
|
['iceConnectionClosed'].forEach(e => mediaHandler.on(e, handleIceConnectionTerminated));
|
||||||
|
|
||||||
const inEchoDTMF = (event) => {
|
Tracker.autorun((c) => {
|
||||||
if (event.body && typeof event.body === 'string') {
|
const selector = { meetingId: Auth.meetingID, userId: Auth.userID };
|
||||||
const dtmf = SIPSession.parseDTMF(event.body);
|
const query = VoiceCallStates.find(selector);
|
||||||
if (dtmf === '0') {
|
|
||||||
fsReady = true;
|
query.observeChanges({
|
||||||
checkIfCallReady();
|
changed: (id, fields) => {
|
||||||
}
|
if (fields.callState === CallStateOptions.IN_ECHO_TEST) {
|
||||||
}
|
fsReady = true;
|
||||||
currentSession.off('dtmf', inEchoDTMF);
|
checkIfCallReady();
|
||||||
};
|
|
||||||
currentSession.on('dtmf', inEchoDTMF);
|
c.stop();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ import clearNote from '/imports/api/note/server/modifiers/clearNote';
|
|||||||
import clearNetworkInformation from '/imports/api/network-information/server/modifiers/clearNetworkInformation';
|
import clearNetworkInformation from '/imports/api/network-information/server/modifiers/clearNetworkInformation';
|
||||||
import clearLocalSettings from '/imports/api/local-settings/server/modifiers/clearLocalSettings';
|
import clearLocalSettings from '/imports/api/local-settings/server/modifiers/clearLocalSettings';
|
||||||
import clearRecordMeeting from './clearRecordMeeting';
|
import clearRecordMeeting from './clearRecordMeeting';
|
||||||
|
import clearVoiceCallStates from '/imports/api/voice-call-states/server/modifiers/clearVoiceCallStates';
|
||||||
|
|
||||||
export default function meetingHasEnded(meetingId) {
|
export default function meetingHasEnded(meetingId) {
|
||||||
removeAnnotationsStreamer(meetingId);
|
removeAnnotationsStreamer(meetingId);
|
||||||
@ -40,6 +41,7 @@ export default function meetingHasEnded(meetingId) {
|
|||||||
clearNetworkInformation(meetingId);
|
clearNetworkInformation(meetingId);
|
||||||
clearLocalSettings(meetingId);
|
clearLocalSettings(meetingId);
|
||||||
clearRecordMeeting(meetingId);
|
clearRecordMeeting(meetingId);
|
||||||
|
clearVoiceCallStates(meetingId);
|
||||||
|
|
||||||
return Logger.info(`Cleared Meetings with id ${meetingId}`);
|
return Logger.info(`Cleared Meetings with id ${meetingId}`);
|
||||||
});
|
});
|
||||||
|
13
bigbluebutton-html5/imports/api/voice-call-states/index.js
Normal file
13
bigbluebutton-html5/imports/api/voice-call-states/index.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
|
||||||
|
const VoiceCallStates = new Mongo.Collection('voiceCallStates');
|
||||||
|
|
||||||
|
if (Meteor.isServer) {
|
||||||
|
// types of queries for the voice users:
|
||||||
|
// 1. intId
|
||||||
|
// 2. meetingId, intId
|
||||||
|
|
||||||
|
VoiceCallStates._ensureIndex({ meetingId: 1, userId: 1 });
|
||||||
|
}
|
||||||
|
|
||||||
|
export default VoiceCallStates;
|
@ -0,0 +1,4 @@
|
|||||||
|
import RedisPubSub from '/imports/startup/server/redis';
|
||||||
|
import handleVoiceCallStateEvent from './handlers/voiceCallStateEvent';
|
||||||
|
|
||||||
|
RedisPubSub.on('VoiceCallStateEvtMsg', handleVoiceCallStateEvent);
|
@ -0,0 +1,48 @@
|
|||||||
|
import { check } from 'meteor/check';
|
||||||
|
import VoiceCallState from '/imports/api/voice-call-states';
|
||||||
|
import Logger from '/imports/startup/server/logger';
|
||||||
|
|
||||||
|
// "CALL_STARTED", "IN_ECHO_TEST", "IN_CONFERENCE", "CALL_ENDED"
|
||||||
|
|
||||||
|
export default function handleVoiceCallStateEvent({ body }, meetingId) {
|
||||||
|
const {
|
||||||
|
voiceConf,
|
||||||
|
clientSession,
|
||||||
|
userId,
|
||||||
|
callerName,
|
||||||
|
callState,
|
||||||
|
} = body;
|
||||||
|
|
||||||
|
check(meetingId, String);
|
||||||
|
check(voiceConf, String);
|
||||||
|
check(clientSession, String);
|
||||||
|
check(userId, String);
|
||||||
|
check(callerName, String);
|
||||||
|
check(callState, String);
|
||||||
|
|
||||||
|
const selector = {
|
||||||
|
meetingId,
|
||||||
|
userId,
|
||||||
|
clientSession,
|
||||||
|
};
|
||||||
|
|
||||||
|
const modifier = {
|
||||||
|
$set: {
|
||||||
|
meetingId,
|
||||||
|
userId,
|
||||||
|
voiceConf,
|
||||||
|
clientSession,
|
||||||
|
callState,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const cb = (err) => {
|
||||||
|
if (err) {
|
||||||
|
return Logger.error(`Update voice call state=${userId}: ${err}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Logger.debug(`Update voice call state=${userId} meeting=${meetingId} clientSession=${clientSession}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
return VoiceCallState.upsert(selector, modifier, cb);
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
import './eventHandlers';
|
||||||
|
import './publishers';
|
@ -0,0 +1,14 @@
|
|||||||
|
import Logger from '/imports/startup/server/logger';
|
||||||
|
import VoiceCallStates from '/imports/api/voice-users';
|
||||||
|
|
||||||
|
export default function clearVoiceCallStates(meetingId) {
|
||||||
|
if (meetingId) {
|
||||||
|
return VoiceCallStates.remove({ meetingId }, () => {
|
||||||
|
Logger.info(`Cleared VoiceCallStates in (${meetingId})`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return VoiceCallStates.remove({}, () => {
|
||||||
|
Logger.info('Cleared VoiceCallStates in all meetings');
|
||||||
|
});
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
import VoiceCallStates from '/imports/api/voice-call-states';
|
||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
import Logger from '/imports/startup/server/logger';
|
||||||
|
import { extractCredentials } from '/imports/api/common/server/helpers';
|
||||||
|
|
||||||
|
function voiceCallStates() {
|
||||||
|
if (!this.userId) {
|
||||||
|
return VoiceCallStates.find({ meetingId: '' });
|
||||||
|
}
|
||||||
|
const { meetingId, requesterUserId } = extractCredentials(this.userId);
|
||||||
|
|
||||||
|
Logger.debug(`Publishing Voice Call States for ${meetingId} ${requesterUserId}`);
|
||||||
|
|
||||||
|
return VoiceCallStates.find({ meetingId, userId: requesterUserId });
|
||||||
|
}
|
||||||
|
|
||||||
|
function publish(...args) {
|
||||||
|
const boundVoiceCallStates = voiceCallStates.bind(this);
|
||||||
|
return boundVoiceCallStates(...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
Meteor.publish('voice-call-states', publish);
|
@ -0,0 +1,8 @@
|
|||||||
|
const CallStateOptions = {
|
||||||
|
CALL_STARTED: 'CALL_STARTED',
|
||||||
|
IN_ECHO_TEST: 'IN_ECHO_TEST',
|
||||||
|
IN_CONFERENCE: 'IN_CONFERENCE',
|
||||||
|
CALL_ENDED: 'CALL_ENDED',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CallStateOptions;
|
@ -20,6 +20,7 @@ const SUBSCRIPTIONS = [
|
|||||||
'voiceUsers', 'whiteboard-multi-user', 'screenshare', 'group-chat',
|
'voiceUsers', 'whiteboard-multi-user', 'screenshare', 'group-chat',
|
||||||
'presentation-pods', 'users-settings', 'guestUser', 'users-infos', 'note', 'meeting-time-remaining',
|
'presentation-pods', 'users-settings', 'guestUser', 'users-infos', 'note', 'meeting-time-remaining',
|
||||||
'network-information', 'ping-pong', 'local-settings', 'users-typing', 'record-meetings', 'video-streams',
|
'network-information', 'ping-pong', 'local-settings', 'users-typing', 'record-meetings', 'video-streams',
|
||||||
|
'voice-call-states',
|
||||||
];
|
];
|
||||||
|
|
||||||
class Subscriptions extends Component {
|
class Subscriptions extends Component {
|
||||||
|
@ -26,7 +26,7 @@ import '/imports/api/external-videos/server';
|
|||||||
import '/imports/api/guest-users/server';
|
import '/imports/api/guest-users/server';
|
||||||
import '/imports/api/ping-pong/server';
|
import '/imports/api/ping-pong/server';
|
||||||
import '/imports/api/local-settings/server';
|
import '/imports/api/local-settings/server';
|
||||||
|
import '/imports/api/voice-call-states/server';
|
||||||
|
|
||||||
// Commons
|
// Commons
|
||||||
import '/imports/api/log-client/server';
|
import '/imports/api/log-client/server';
|
||||||
|
Loading…
Reference in New Issue
Block a user