mirror of
https://github.com/jambonz/jambonz-feature-server.git
synced 2025-12-20 16:50:39 +00:00
* fixed transcription is not received when call is terminated * wip * fixed failing testcases * wip * wip * wip * wip * should not do gracefulshutdown on stopAmd
116 lines
3.5 KiB
JavaScript
116 lines
3.5 KiB
JavaScript
const {
|
|
JAMBONES_USE_FREESWITCH_TIMER_FD,
|
|
JAMBONES_MEDIA_TIMEOUT_MS,
|
|
JAMBONES_MEDIA_HOLD_TIMEOUT_MS,
|
|
JAMBONES_TRANSCRIBE_EP_DESTROY_DELAY_MS,
|
|
} = require('../config');
|
|
const { sleepFor } = require('./helpers');
|
|
|
|
const createMediaEndpoint = async(srf, logger, {
|
|
activeMs,
|
|
drachtioFsmrfOptions = {},
|
|
onHoldMusic,
|
|
inbandDtmfEnabled,
|
|
mediaTimeoutHandler,
|
|
} = {}) => {
|
|
const { getFreeswitch } = srf.locals;
|
|
const ms = activeMs || getFreeswitch();
|
|
if (!ms)
|
|
throw new Error('no available Freeswitch for creating media endpoint');
|
|
|
|
const ep = await ms.createEndpoint(drachtioFsmrfOptions);
|
|
|
|
// Configure the endpoint
|
|
const opts = {
|
|
...(onHoldMusic && {holdMusic: `shout://${onHoldMusic.replace(/^https?:\/\//, '')}`}),
|
|
...(JAMBONES_USE_FREESWITCH_TIMER_FD && {timer_name: 'timerfd'}),
|
|
...(JAMBONES_MEDIA_TIMEOUT_MS && {media_timeout: JAMBONES_MEDIA_TIMEOUT_MS}),
|
|
...(JAMBONES_MEDIA_HOLD_TIMEOUT_MS && {media_hold_timeout: JAMBONES_MEDIA_HOLD_TIMEOUT_MS})
|
|
};
|
|
if (Object.keys(opts).length > 0) {
|
|
ep.set(opts);
|
|
}
|
|
// inbandDtmfEnabled
|
|
if (inbandDtmfEnabled) {
|
|
// https://developer.signalwire.com/freeswitch/FreeSWITCH-Explained/Modules/mod-dptools/6587132/#0-about
|
|
ep.execute('start_dtmf').catch((err) => {
|
|
logger.error('Error starting inband DTMF', { error: err });
|
|
});
|
|
ep.inbandDtmfEnabled = true;
|
|
}
|
|
// Handle Media Timeout
|
|
if (mediaTimeoutHandler) {
|
|
ep.once('destroy', (evt) => {
|
|
mediaTimeoutHandler(evt, ep);
|
|
});
|
|
}
|
|
// Handle graceful shutdown for endpoint if required
|
|
if (JAMBONES_TRANSCRIBE_EP_DESTROY_DELAY_MS > 0) {
|
|
const getEpGracefulShutdownPromise = () => {
|
|
if (!ep.gracefulShutdownPromise) {
|
|
ep.gracefulShutdownPromise = new Promise((resolve) => {
|
|
// this resolver will be called when stt task received transcription.
|
|
ep.gracefulShutdownResolver = () => {
|
|
resolve();
|
|
ep.gracefulShutdownPromise = null;
|
|
};
|
|
});
|
|
}
|
|
return ep.gracefulShutdownPromise;
|
|
};
|
|
|
|
const gracefulShutdownHandler = async() => {
|
|
// resolve when one of the following happens:
|
|
// 1. stt task received transcription
|
|
// 2. JAMBONES_TRANSCRIBE_EP_DESTROY_DELAY_MS passed
|
|
await Promise.race([
|
|
getEpGracefulShutdownPromise(),
|
|
sleepFor(JAMBONES_TRANSCRIBE_EP_DESTROY_DELAY_MS)
|
|
]);
|
|
};
|
|
|
|
const origStartTranscription = ep.startTranscription.bind(ep);
|
|
ep.startTranscription = async(...args) => {
|
|
try {
|
|
const result = await origStartTranscription(...args);
|
|
ep.isTranscribeActive = true;
|
|
return result;
|
|
} catch (err) {
|
|
ep.isTranscribeActive = false;
|
|
throw err;
|
|
}
|
|
};
|
|
|
|
const origStopTranscription = ep.stopTranscription.bind(ep);
|
|
ep.stopTranscription = async(opts = {}, ...args) => {
|
|
const { gracefulShutdown = true, ...others } = opts;
|
|
if (ep.isTranscribeActive && gracefulShutdown) {
|
|
// only wait for graceful shutdown if transcription is active
|
|
await gracefulShutdownHandler();
|
|
}
|
|
try {
|
|
const result = await origStopTranscription({...others}, ...args);
|
|
ep.isTranscribeActive = false;
|
|
return result;
|
|
} catch (err) {
|
|
ep.isTranscribeActive = false;
|
|
throw err;
|
|
}
|
|
};
|
|
|
|
const origDestroy = ep.destroy.bind(ep);
|
|
ep.destroy = async() => {
|
|
if (ep.isTranscribeActive) {
|
|
await gracefulShutdownHandler();
|
|
}
|
|
return await origDestroy();
|
|
};
|
|
}
|
|
|
|
return ep;
|
|
};
|
|
|
|
module.exports = {
|
|
createMediaEndpoint,
|
|
};
|