diff --git a/lib/call-session.js b/lib/call-session.js index e9f82d8..6c43932 100644 --- a/lib/call-session.js +++ b/lib/call-session.js @@ -1,5 +1,4 @@ const Emitter = require('events'); -const sdpTransform = require('sdp-transform'); const SrsClient = require('@jambonz/siprec-client-utils'); const { makeRtpEngineOpts, @@ -10,7 +9,6 @@ const { makePartnerFullMediaReleaseKey, isValidDomainOrIP, removeVideoSdp, - determineAnswerCodec } = require('./utils'); const { MediaPath } = require('./constants.json'); const {forwardInDialogRequests} = require('drachtio-fn-b2b-sugar'); @@ -96,19 +94,6 @@ const initCdr = (req, invite) => { }; }; -const updateRtpEngineFlags = (sdp, opts) => { - try { - const parsed = sdpTransform.parse(sdp); - const codec = parsed.media[0].rtp[0].codec; - // Only add telephone-event support, don't restrict to specific G.711 codec yet - // This allows far end to choose between PCMU/PCMA freely - if (['PCMU', 'PCMA'].includes(codec)) { - opts.flags.push('codec-accept-telephone-event'); - } - } catch {} - return opts; -}; - class CallSession extends Emitter { constructor(logger, req, res) { super(); @@ -398,13 +383,13 @@ class CallSession extends Emitter { const toPublic = uris.some((u) => u.private_network === false); let isOfferUpdatedToPrivate = toPrivate && !toPublic; - const opts = updateRtpEngineFlags(this.req.body, { + const opts = { ...this.rtpEngineOpts.common, ...this.rtpEngineOpts.uac.mediaOpts, 'from-tag': this.rtpEngineOpts.uas.tag, direction: ['private', toPublic ? 'public' : 'private'], sdp: this.req.body - }); + }; let response = await this.offer(opts); this.logger.debug({offer: opts, response}, 'initial offer to rtpengine'); if ('ok' !== response.result) { @@ -516,7 +501,7 @@ class CallSession extends Emitter { }) }; const p = proxy ? ` via ${proxy}` : ''; - this.logger.info({uri, p}, `sending INVITE to ${uri}${p}`); + this.logger.info({uri, p}, `sending INVITE${p}`); } /* now launch an outbound call attempt */ @@ -557,15 +542,16 @@ class CallSession extends Emitter { localSdpA: async(sdp, res) => { this.rtpEngineOpts.uac.tag = res.getParsedHeader('To').params.tag; - // Determine which codec to use based on far end negotiation - const {codec} = determineAnswerCodec(sdp, this.req.body, this.logger); - const opts = { ...this.rtpEngineOpts.common, ...this.rtpEngineOpts.uas.mediaOpts, 'from-tag': this.rtpEngineOpts.uas.tag, 'to-tag': this.rtpEngineOpts.uac.tag, - flags: ['single codec', 'inject DTMF', `codec-accept-${codec}`, 'codec-accept-telephone-event'], + flags: [ + 'single codec', + 'inject DTMF', + 'reuse codecs', + ], sdp }; const response = await this.answer(opts); diff --git a/lib/utils.js b/lib/utils.js index 09156a5..33c5133 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -16,8 +16,8 @@ function makeRtpEngineOpts(req, srcIsUsingSrtp, dstIsUsingSrtp, padCrypto, teams } const srtpOpts = teams ? srtpCopy['teams'] : srtpCopy['default']; - const dstOpts = dstIsUsingSrtp ? srtpOpts : rtpCopy; - const srcOpts = srcIsUsingSrtp ? srtpOpts : rtpCopy; + const dstOpts = JSON.parse(JSON.stringify(dstIsUsingSrtp ? srtpOpts : rtpCopy)); + const srcOpts = JSON.parse(JSON.stringify(srcIsUsingSrtp ? srtpOpts : rtpCopy)); /** Allow feature server to send DTMF to the call excepts call from/to teams */ if (!teams) { @@ -41,6 +41,16 @@ function makeRtpEngineOpts(req, srcIsUsingSrtp, dstIsUsingSrtp, padCrypto, teams 'replace': ['origin', 'session-connection'], 'record call': process.env.JAMBONES_RECORD_ALL_CALLS ? 'yes' : 'no' }; + + const codec = { + accept: ['PCMU', 'PCMA', 'telephone-event'], + ...(process.env.JAMBONES_CODEC_OFFER_WITH_ORDER && + { + offer: process.env.JAMBONES_CODEC_OFFER_WITH_ORDER.split(','), + strip: 'all' + }), + }; + return { common, uas: { @@ -51,8 +61,7 @@ function makeRtpEngineOpts(req, srcIsUsingSrtp, dstIsUsingSrtp, padCrypto, teams tag: null, mediaOpts: { ...dstOpts, - ...(process.env.JAMBONES_CODEC_OFFER_WITH_ORDER && - { codec: { offer: process.env.JAMBONES_CODEC_OFFER_WITH_ORDER.split(','), strip: 'all' } }), + codec, } } }; @@ -350,54 +359,6 @@ const removeVideoSdp = (sdp) => { return sdpTransform.write(parsedSdp); }; -const determineAnswerCodec = (farEndSdp, featureServerSdp, logger) => { - try { - // Parse both SDPs - const farEndParsed = sdpTransform.parse(farEndSdp); - const fsParsed = sdpTransform.parse(featureServerSdp); - - // Get negotiated codec from far end (first codec in answer) - const negotiatedCodec = farEndParsed.media[0].rtp[0].codec; - - // Get all codecs offered by feature server - const fsCodecs = fsParsed.media[0].rtp.map((r) => r.codec); - - logger.debug({negotiatedCodec, fsCodecs}, 'determineAnswerCodec: analyzing codec negotiation'); - - // If far end negotiated G.711 (PCMU/PCMA) AND it was in the FS offer, pass it through - if (['PCMU', 'PCMA'].includes(negotiatedCodec) && fsCodecs.includes(negotiatedCodec)) { - logger.info({negotiatedCodec}, 'G.711 codec passthrough - no transcoding needed'); - return { - codec: negotiatedCodec, - needsTranscoding: false - }; - } - - // Otherwise, we need to transcode to first G.711 codec in FS offer - const firstG711 = fsCodecs.find((c) => ['PCMU', 'PCMA'].includes(c)); - if (firstG711) { - logger.info({negotiatedCodec, transcodeTarget: firstG711}, 'Transcoding required to G.711'); - return { - codec: firstG711, - needsTranscoding: true - }; - } - - // Fallback: use PCMU - logger.info({negotiatedCodec}, 'No G.711 in FS offer, defaulting to PCMU'); - return { - codec: 'PCMU', - needsTranscoding: true - }; - } catch (err) { - logger.error({err}, 'Error determining answer codec, defaulting to PCMU'); - return { - codec: 'PCMU', - needsTranscoding: true - }; - } -}; - module.exports = { makeRtpEngineOpts, selectHostPort, @@ -414,5 +375,4 @@ module.exports = { makePartnerFullMediaReleaseKey, isValidDomainOrIP, removeVideoSdp, - determineAnswerCodec };