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,
|
||||
logSelectedCandidate,
|
||||
} 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_TAG = MEDIA.mediaTag;
|
||||
@ -47,14 +51,6 @@ class SIPSession {
|
||||
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) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const callExtension = extension ? `${extension}${this.userData.voiceBridge}` : this.userData.voiceBridge;
|
||||
@ -119,8 +115,10 @@ class SIPSession {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.inEchoTest = false;
|
||||
|
||||
const timeout = setInterval(() => {
|
||||
clearInterval(timeout);
|
||||
let trackerControl = null;
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
trackerControl.stop();
|
||||
logger.error({ logCode: 'sip_js_transfer_timed_out' }, 'Timeout on transferring from echo test to conference');
|
||||
this.callback({
|
||||
status: this.baseCallStates.failed,
|
||||
@ -136,15 +134,22 @@ class SIPSession {
|
||||
// This is is the call transfer code ask @chadpilkey
|
||||
this.currentSession.dtmf(1);
|
||||
|
||||
this.currentSession.on('dtmf', (event) => {
|
||||
if (event.body && (typeof event.body === 'string')) {
|
||||
const key = SIPSession.parseDTMF(event.body);
|
||||
if (key === '7') {
|
||||
clearInterval(timeout);
|
||||
onTransferSuccess();
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
Tracker.autorun((c) => {
|
||||
trackerControl = c;
|
||||
const selector = { meetingId: Auth.meetingID, userId: Auth.userID };
|
||||
const query = VoiceCallStates.find(selector);
|
||||
|
||||
query.observeChanges({
|
||||
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));
|
||||
|
||||
const inEchoDTMF = (event) => {
|
||||
if (event.body && typeof event.body === 'string') {
|
||||
const dtmf = SIPSession.parseDTMF(event.body);
|
||||
if (dtmf === '0') {
|
||||
fsReady = true;
|
||||
checkIfCallReady();
|
||||
}
|
||||
}
|
||||
currentSession.off('dtmf', inEchoDTMF);
|
||||
};
|
||||
currentSession.on('dtmf', inEchoDTMF);
|
||||
Tracker.autorun((c) => {
|
||||
const selector = { meetingId: Auth.meetingID, userId: Auth.userID };
|
||||
const query = VoiceCallStates.find(selector);
|
||||
|
||||
query.observeChanges({
|
||||
changed: (id, fields) => {
|
||||
if (fields.callState === CallStateOptions.IN_ECHO_TEST) {
|
||||
fsReady = true;
|
||||
checkIfCallReady();
|
||||
|
||||
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 clearLocalSettings from '/imports/api/local-settings/server/modifiers/clearLocalSettings';
|
||||
import clearRecordMeeting from './clearRecordMeeting';
|
||||
import clearVoiceCallStates from '/imports/api/voice-call-states/server/modifiers/clearVoiceCallStates';
|
||||
|
||||
export default function meetingHasEnded(meetingId) {
|
||||
removeAnnotationsStreamer(meetingId);
|
||||
@ -40,6 +41,7 @@ export default function meetingHasEnded(meetingId) {
|
||||
clearNetworkInformation(meetingId);
|
||||
clearLocalSettings(meetingId);
|
||||
clearRecordMeeting(meetingId);
|
||||
clearVoiceCallStates(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',
|
||||
'presentation-pods', 'users-settings', 'guestUser', 'users-infos', 'note', 'meeting-time-remaining',
|
||||
'network-information', 'ping-pong', 'local-settings', 'users-typing', 'record-meetings', 'video-streams',
|
||||
'voice-call-states',
|
||||
];
|
||||
|
||||
class Subscriptions extends Component {
|
||||
|
@ -26,7 +26,7 @@ import '/imports/api/external-videos/server';
|
||||
import '/imports/api/guest-users/server';
|
||||
import '/imports/api/ping-pong/server';
|
||||
import '/imports/api/local-settings/server';
|
||||
|
||||
import '/imports/api/voice-call-states/server';
|
||||
|
||||
// Commons
|
||||
import '/imports/api/log-client/server';
|
||||
|
Loading…
Reference in New Issue
Block a user