Skip to content

Instantly share code, notes, and snippets.

@aylarov
Last active March 24, 2017 06:30
Show Gist options
  • Save aylarov/0a699701815c05f6557a2d4d486800dc to your computer and use it in GitHub Desktop.
Save aylarov/0a699701815c05f6557a2d4d486800dc to your computer and use it in GitHub Desktop.
VoxEngine scenario for Babelfish app - Gatekeeper
require(Modules.ASR);
require(Modules.Recorder);
/**
* Conference Gatekeeper
* Handle inbound calls and route them to the conference
*/
var call,
conferenceId,
conf,
API_KEY = "YOUR_GOOGLE_TRANSLATE_API_KEY",
translateFrom,
translateTo,
asrLanguage,
ttsLanguage,
ttsEnabled = false,
voice = null,
asr, vad, ts, ts2;
var decodeHtmlEntity = function (str) {
return str.replace(/&#(\d+);/g, function (match, dec) {
return String.fromCharCode(dec);
});
};
/**
* Inbound call handler
*/
VoxEngine.addEventListener(AppEvents.CallAlerting, function (e) {
// Get conference id from headers
conferenceId = e.headers['X-Conference-Id'];
Logger.write('User ' + e.callerid + ' is joining conference ' + conferenceId);
call = e.call;
/**
* Add event listeners
*/
call.addEventListener(CallEvents.Connected, sdkCallConnected);
call.addEventListener(CallEvents.Disconnected, function (e) {
VoxEngine.terminate();
});
call.addEventListener(CallEvents.Failed, function (e) {
VoxEngine.terminate();
});
call.addEventListener(CallEvents.MessageReceived, function (e) {
// Process text message arrived from client
Logger.write("Message Received: " + e.text);
try {
var msg = JSON.parse(e.text);
} catch (err) {
Logger.write(err);
}
if (msg.type == "ICE_FAILED") {
// P2P call ICE problems
conf.sendMessage(e.text);
} else if (msg.type == "ENABLE_TTS") {
// Text-to-speech enabled
ttsEnabled = true;
voice = msg.voice;
Logger.write("TTS voice: " + voice);
} else if (msg.type == "DISABLE_TTS") {
// Text-to-speech disabled
ttsEnabled = false;
} else if (msg.type == "ASR_START") {
/**
* Start recognition and translation
*/
translateFrom = msg.fromLanguage;
translateTo = msg.toLanguage;
e.call.handleMicStatus(true);
e.call.addEventListener(CallEvents.MicStatusChange, handleMicStatus);
switch (translateFrom) {
case "en":
asrLanguage = ASRLanguage.ENGLISH_US;
break;
case "ru":
asrLanguage = ASRLanguage.RUSSIAN_RU;
break;
case "de":
asrLanguage = ASRLanguage.GERMAN_DE;
break;
case "fr":
asrLanguage = ASRLanguage.FRENCH_FR;
break;
case "es":
asrLanguage = ASRLanguage.SPANISH_ES;
break;
}
/**
* Create ASR instance
*/
asr = VoxEngine.createASR({
lang: asrLanguage,
singleUtterance: true,
interimResults: true
});
/**
* Notify client about SpeechCaptured event
*/
asr.addEventListener(ASREvents.SpeechCaptured, function (asrevent) {
e.call.sendMessage(JSON.stringify({
type: "SPEECH_CAPTURED"
}));
});
/**
* Notify client about CaptureStarted event
*/
asr.addEventListener(ASREvents.CaptureStarted, function (asrevent) {
clearTimeout(ts);
e.call.sendMessage(JSON.stringify({
type: "CAPTURE_STARTED"
}));
});
/**
* Process interim recognition result
*/
asr.addEventListener(ASREvents.InterimResult, function (asrevent) {
e.call.sendMessage(JSON.stringify({
type: "RESULT",
text: asrevent.text,
confidence: asrevent.confidence,
stability: asrevent.stability,
result_type: "INTERIM_RESULT"
}));
});
/**
* Process final recognition result
*/
asr.addEventListener(ASREvents.Result, function (asrevent) {
// Send result to conference that will re-send it to other participant
conf.sendMessage(JSON.stringify({
type: "RESULT",
text: asrevent.text,
confidence: asrevent.confidence,
result_type: "RECOGNITION"
}));
// Send result to client
e.call.sendMessage(JSON.stringify({
type: "RESULT",
text: asrevent.text,
confidence: asrevent.confidence,
result_type: "LOCAL_RECOGNITION"
}));
/**
* Translate result using Google Translate API
*/
Logger.write("Making HTTP request for translation " + translateFrom + " => " + translateTo);
Net.httpRequest("https://www.googleapis.com/language/translate/v2?key=" +
API_KEY +
"&source=" + translateFrom +
"&target=" + translateTo +
"&q=" + encodeURIComponent(asrevent.text),
function (result) {
handleTranslationResult(result, asrevent.confidence, e.call);
});
});
/**
* Start streaming call audio to ASR instance
*/
e.call.sendMediaTo(asr);
} else if (msg.type == "ASR_STOP") {
/**
* Stop ASR
*/
e.call.handleMicStatus(false);
e.call.removeEventListener(CallEvents.MicStatusChange);
e.call.stopMediaTo(asr);
asr.stop();
}
});
// Answer the call
call.answer();
});
/**
* Process the translation result received from Google Translate API
*/
function handleTranslationResult(e, confidence, c) {
Logger.write("handleTranslationResult code: " + e.code);
if (e.code == 200) {
try {
var result = JSON.parse(e.text);
Logger.write("Translation result: " + result.data.translations[0].translatedText);
// Send the translation result to client
call.sendMessage(JSON.stringify({
type: "RESULT",
text: decodeHtmlEntity(result.data.translations[0].translatedText),
confidence: confidence,
result_type: "LOCAL_TRANSLATION"
}));
// Send the translation result to the conference for other participant
conf.sendMessage(JSON.stringify({
type: "RESULT",
text: decodeHtmlEntity(result.data.translations[0].translatedText),
confidence: confidence,
result_type: "TRANSLATION",
tts: ttsEnabled,
language: translateTo,
voice: voice
}));
} catch (err) {
Logger.write(JSON.stringify(err));
}
}
}
/**
* Handle microphone status
*/
function handleMicStatus(e) {
if (e.active) {
vad = true;
e.call.sendMessage(JSON.stringify({
type: "VAD",
status: true
}));
} else {
vad = false;
e.call.sendMessage(JSON.stringify({
type: "VAD",
status: false
}));
}
}
/**
* Connected handler
*/
function sdkCallConnected(e) {
Logger.write('Joining conference');
// Call standalone conference with specified conference id
conf = VoxEngine.callConference('conf_' + conferenceId, call.callerid(), call.displayName(), {
"X-ClientType": "web"
});
Logger.write('CallerID: ' + call.callerid() + ' DisplayName: ' + call.displayName());
// Add event listeners
conf.addEventListener(CallEvents.Connected, function (e) {
Logger.write("Conference Connected");
// Send media between client call and conference
VoxEngine.sendMediaBetween(conf, call);
// Notify client that conference call connected
call.sendMessage(JSON.stringify({
type: "CONF",
result: "connected"
}));
});
conf.addEventListener(CallEvents.Disconnected, VoxEngine.terminate);
conf.addEventListener(CallEvents.Failed, function (e) {
/**
* Conference scenario rejects calls if 2 participants are already connected
*/
if (e.headers["X-Reason"] == "ROOM_IS_FULL") {
call.say("The room is full", Language.US_ENGLISH_FEMALE);
call.addEventListener(CallEvents.PlaybackFinished, function (event) {
call.hangup({
"X-Reason": e.headers["X-Reason"]
});
});
}
});
/**
* Process messages coming from the conference
*/
conf.addEventListener(CallEvents.MessageReceived, function (e) {
var result = JSON.parse(e.text);
if (result["result_type"] == "TRANSLATION") {
if (result["tts"] == true) {
switch (result["language"]) {
case "en":
if (result["voice"] == 0) ttsLanguage = Language.US_ENGLISH_MALE;
else ttsLanguage = Language.US_ENGLISH_FEMALE;
break;
case "ru":
if (result["voice"] == 0) ttsLanguage = Language.RU_RUSSIAN_MALE;
else ttsLanguage = Language.RU_RUSSIAN_FEMALE;
break;
case "de":
if (result["voice"] == 0) ttsLanguage = Language.EUR_GERMAN_MALE;
else ttsLanguage = Language.EUR_GERMAN_FEMALE;
break;
case "fr":
if (result["voice"] == 0) ttsLanguage = Language.EUR_FRENCH_MALE;
else ttsLanguage = Language.EUR_FRENCH_FEMALE;
break;
case "es":
if (result["voice"] == 0) ttsLanguage = Language.EUR_SPANISH_MALE;
else ttsLanguage = Language.EUR_SPANISH_FEMALE;
break;
}
call.say(result.text, ttsLanguage);
}
}
call.sendMessage(e.text);
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment