start/stop/pause/resume recording success when one of siprec server success. (#131)

* start/stop/pause/resume recording success when one of siprec server success.

* wip

* wip

* update customer header for pause and resume

* allow timeout for siprec action

* wip

* wip

* wip

* update siprec client utils
This commit is contained in:
Hoan Luu Huu
2024-03-06 01:05:42 +07:00
committed by GitHub
parent 2747bc15d6
commit f5be95006c
3 changed files with 56 additions and 22 deletions

View File

@@ -67,6 +67,7 @@ class CallSession extends Emitter {
this.account_sid = req.locals.account_sid; this.account_sid = req.locals.account_sid;
this.service_provider_sid = req.locals.service_provider_sid; this.service_provider_sid = req.locals.service_provider_sid;
this.srsClients = []; this.srsClients = [];
this.recordingNoAnswerTimeout = (process.env.JAMBONES_RECORDING_NO_ANSWER_TIMEOUT || 2) * 1000;
} }
get isFromMSTeams() { get isFromMSTeams() {
@@ -335,6 +336,22 @@ class CallSession extends Emitter {
dlg.on('modify', this._onReinvite.bind(this, dlg)); dlg.on('modify', this._onReinvite.bind(this, dlg));
} }
_startRecordingNoAnswerTimer(res) {
this._clearRecordingNoAnswerTimer();
this.recordingNoAnswerTimer = setTimeout(() => {
this.logger.info('No response from SipRec server, return error to feature server');
this.isRecordingNoAnswerResponded = true;
res.send(400);
}, this.recordingNoAnswerTimeout);
}
_clearRecordingNoAnswerTimer() {
if (this.recordingNoAnswerTimer) {
clearTimeout(this.recordingNoAnswerTimer);
this.recordingNoAnswerTimer = null;
}
}
_stopRecording() { _stopRecording() {
if (this.srsClients.length) { if (this.srsClients.length) {
this.srsClients.forEach((c) => c.stop()); this.srsClients.forEach((c) => c.stop());
@@ -706,12 +723,12 @@ Duration=${payload.duration} `
} }
else if (reason.includes('CallRecording')) { else if (reason.includes('CallRecording')) {
let succeeded = false; let succeeded = false;
const headers = contentType === 'application/json' && req.body ? JSON.parse(req.body) : {};
if (reason === 'startCallRecording') { if (reason === 'startCallRecording') {
const from = this.req.getParsedHeader('From'); const from = this.req.getParsedHeader('From');
const to = this.req.getParsedHeader('To'); const to = this.req.getParsedHeader('To');
const aorFrom = from.uri; const aorFrom = from.uri;
const aorTo = to.uri; const aorTo = to.uri;
const headers = contentType === 'application/json' && req.body ? JSON.parse(req.body) : {};
this.logger.info({to, from}, 'startCallRecording request for a call'); this.logger.info({to, from}, 'startCallRecording request for a call');
const srsUrl = req.get('X-Srs-Url'); const srsUrl = req.get('X-Srs-Url');
@@ -755,11 +772,14 @@ Duration=${payload.duration} `
headers headers
})); }));
try { try {
succeeded = (await Promise.all( this._startRecordingNoAnswerTimer(res);
this.srsClients.map((c) => c.start()) await Promise.any(this.srsClients.map((c) => c.start()));
)).every((r) => r); // Only take who success accept request.
this.srsClients = this.srsClients.filter((c) => c.activated);
succeeded = true;
} catch (err) { } catch (err) {
this.logger.error({err}, 'Error starting SipRec call recording'); this.logger.error({err}, 'Error starting SipRec call recording');
succeeded = false;
} }
} }
else if (reason === 'stopCallRecording') { else if (reason === 'stopCallRecording') {
@@ -769,11 +789,12 @@ Duration=${payload.duration} `
return; return;
} }
try { try {
succeeded = (await Promise.all( this._startRecordingNoAnswerTimer(res);
this.srsClients.map((c) => c.stop()) await Promise.any(this.srsClients.map((c) => c.stop()));
)).every((r) => r); succeeded = true;
} catch (err) { } catch (err) {
this.logger.error({err}, 'Error stopping SipRec call recording'); this.logger.error({err}, 'Error stopping SipRec call recording');
succeeded = false;
} }
this.srsClients = []; this.srsClients = [];
} }
@@ -783,9 +804,14 @@ Duration=${payload.duration} `
res.send(400); res.send(400);
return; return;
} }
succeeded = (await Promise.all( try {
this.srsClients.map((c) => c.pause()) this._startRecordingNoAnswerTimer(res);
)).every((r) => r); await Promise.any(this.srsClients.map((c) => c.pause({headers})));
succeeded = true;
} catch (err) {
this.logger.error({err}, 'Error pausing SipRec call recording');
succeeded = false;
}
} }
else if (reason === 'resumeCallRecording') { else if (reason === 'resumeCallRecording') {
if (!this.srsClients.length || !this.srsClients.every((c) => c.paused)) { if (!this.srsClients.length || !this.srsClients.every((c) => c.paused)) {
@@ -793,11 +819,19 @@ Duration=${payload.duration} `
this.logger.info('discarding invalid resumeCallRecording request'); this.logger.info('discarding invalid resumeCallRecording request');
return; return;
} }
succeeded = (await Promise.all( try {
this.srsClients.map((c) => c.resume()) this._startRecordingNoAnswerTimer(res);
)).every((r) => r); await Promise.any(this.srsClients.map((c) => c.resume({headers})));
succeeded = true;
} catch (err) {
this.logger.error({err}, 'Error resuming SipRec call recording');
succeeded = false;
}
}
if (!this.isRecordingNoAnswerResponded) {
this._clearRecordingNoAnswerTimer();
res.send(succeeded ? 200 : 503);
} }
res.send(succeeded ? 200 : 503);
} else if (reason.includes('Dtmf')) { } else if (reason.includes('Dtmf')) {
const arr = /Signal=\s*([0-9#*])/.exec(req.body); const arr = /Signal=\s*([0-9#*])/.exec(req.body);
if (!arr) { if (!arr) {

14
package-lock.json generated
View File

@@ -16,7 +16,7 @@
"@jambonz/http-health-check": "^0.0.1", "@jambonz/http-health-check": "^0.0.1",
"@jambonz/realtimedb-helpers": "^0.8.7", "@jambonz/realtimedb-helpers": "^0.8.7",
"@jambonz/rtpengine-utils": "^0.4.4", "@jambonz/rtpengine-utils": "^0.4.4",
"@jambonz/siprec-client-utils": "^0.2.6", "@jambonz/siprec-client-utils": "^0.2.7",
"@jambonz/stats-collector": "^0.1.9", "@jambonz/stats-collector": "^0.1.9",
"@jambonz/time-series": "^0.2.5", "@jambonz/time-series": "^0.2.5",
"bent": "^7.3.12", "bent": "^7.3.12",
@@ -1850,9 +1850,9 @@
} }
}, },
"node_modules/@jambonz/siprec-client-utils": { "node_modules/@jambonz/siprec-client-utils": {
"version": "0.2.6", "version": "0.2.7",
"resolved": "https://registry.npmjs.org/@jambonz/siprec-client-utils/-/siprec-client-utils-0.2.6.tgz", "resolved": "https://registry.npmjs.org/@jambonz/siprec-client-utils/-/siprec-client-utils-0.2.7.tgz",
"integrity": "sha512-z2x6nghLaCfOBPcr36f+1vxsV557X3z5JW1L1RxZg8YPWkTboNIHyHxtEcAua7V9g6EB4G1qv2KDwA+iE5n5Ww==", "integrity": "sha512-VztOToBfXnOphg/y6kO+lBYqoDH7X5Ci0daXT5zQ8v5NnaZw+UwxGeFPX3knIR3r5pmzUld0f2giFOuD4ZOF8w==",
"dependencies": { "dependencies": {
"sdp-transform": "^2.14.1", "sdp-transform": "^2.14.1",
"uuid": "^8.3.2" "uuid": "^8.3.2"
@@ -7548,9 +7548,9 @@
} }
}, },
"@jambonz/siprec-client-utils": { "@jambonz/siprec-client-utils": {
"version": "0.2.6", "version": "0.2.7",
"resolved": "https://registry.npmjs.org/@jambonz/siprec-client-utils/-/siprec-client-utils-0.2.6.tgz", "resolved": "https://registry.npmjs.org/@jambonz/siprec-client-utils/-/siprec-client-utils-0.2.7.tgz",
"integrity": "sha512-z2x6nghLaCfOBPcr36f+1vxsV557X3z5JW1L1RxZg8YPWkTboNIHyHxtEcAua7V9g6EB4G1qv2KDwA+iE5n5Ww==", "integrity": "sha512-VztOToBfXnOphg/y6kO+lBYqoDH7X5Ci0daXT5zQ8v5NnaZw+UwxGeFPX3knIR3r5pmzUld0f2giFOuD4ZOF8w==",
"requires": { "requires": {
"sdp-transform": "^2.14.1", "sdp-transform": "^2.14.1",
"uuid": "^8.3.2" "uuid": "^8.3.2"

View File

@@ -29,7 +29,7 @@
"@jambonz/http-health-check": "^0.0.1", "@jambonz/http-health-check": "^0.0.1",
"@jambonz/realtimedb-helpers": "^0.8.7", "@jambonz/realtimedb-helpers": "^0.8.7",
"@jambonz/rtpengine-utils": "^0.4.4", "@jambonz/rtpengine-utils": "^0.4.4",
"@jambonz/siprec-client-utils": "^0.2.6", "@jambonz/siprec-client-utils": "^0.2.7",
"@jambonz/stats-collector": "^0.1.9", "@jambonz/stats-collector": "^0.1.9",
"@jambonz/time-series": "^0.2.5", "@jambonz/time-series": "^0.2.5",
"@jambonz/digest-utils": "^0.0.3", "@jambonz/digest-utils": "^0.0.3",