ringcentral-softphone 1.3.6 → 1.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/call-session/inbound.mjs +2 -0
- package/dist/call-session/inbound.mjs.map +1 -0
- package/dist/call-session/index.mjs +2 -0
- package/dist/call-session/index.mjs.map +1 -0
- package/dist/call-session/outbound.mjs +2 -0
- package/dist/call-session/outbound.mjs.map +1 -0
- package/dist/call-session/streamer.mjs +2 -0
- package/dist/call-session/streamer.mjs.map +1 -0
- package/dist/codec-Bh7v8J-S.d.mts +2 -1
- package/dist/codec-Bh7v8J-S.d.mts.map +1 -0
- package/dist/codec-C-VrtVkq.d.cts +2 -1
- package/dist/codec-C-VrtVkq.d.cts.map +1 -0
- package/dist/codec.mjs +2 -0
- package/dist/codec.mjs.map +1 -0
- package/dist/dtmf-B13Fz2VR.d.mts +2 -1
- package/dist/dtmf-B13Fz2VR.d.mts.map +1 -0
- package/dist/dtmf-DcQ-5vSG.d.cts +2 -1
- package/dist/dtmf-DcQ-5vSG.d.cts.map +1 -0
- package/dist/dtmf.mjs +2 -0
- package/dist/dtmf.mjs.map +1 -0
- package/dist/inbound--wGoGqLS.d.mts +2 -1
- package/dist/inbound--wGoGqLS.d.mts.map +1 -0
- package/dist/inbound-DquvTSj1.d.cts +2 -1
- package/dist/inbound-DquvTSj1.d.cts.map +1 -0
- package/dist/index--UjWgLK-.d.mts +2 -1
- package/dist/index--UjWgLK-.d.mts.map +1 -0
- package/dist/index-BhN2W8AV.d.mts +2 -1
- package/dist/index-BhN2W8AV.d.mts.map +1 -0
- package/dist/index-Cf2Cev52.d.cts +2 -1
- package/dist/index-Cf2Cev52.d.cts.map +1 -0
- package/dist/index-XMDop59x.d.cts +2 -1
- package/dist/index-XMDop59x.d.cts.map +1 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -0
- package/dist/request-B_auLSJn.d.cts +2 -1
- package/dist/request-B_auLSJn.d.cts.map +1 -0
- package/dist/request-pBe7_mYv.d.mts +2 -1
- package/dist/request-pBe7_mYv.d.mts.map +1 -0
- package/dist/response-LRRpY8lX.d.mts +2 -1
- package/dist/response-LRRpY8lX.d.mts.map +1 -0
- package/dist/response-ReKvb5x9.d.cts +2 -1
- package/dist/response-ReKvb5x9.d.cts.map +1 -0
- package/dist/sip-message/inbound/index.mjs +2 -0
- package/dist/sip-message/inbound/index.mjs.map +1 -0
- package/dist/sip-message/outbound/index.mjs +2 -0
- package/dist/sip-message/outbound/index.mjs.map +1 -0
- package/dist/sip-message/outbound/request.mjs +2 -0
- package/dist/sip-message/outbound/request.mjs.map +1 -0
- package/dist/sip-message/outbound/response.mjs +2 -0
- package/dist/sip-message/outbound/response.mjs.map +1 -0
- package/dist/sip-message/response-codes.d.cts +2 -1
- package/dist/sip-message/response-codes.d.cts.map +1 -0
- package/dist/sip-message/response-codes.d.mts +2 -1
- package/dist/sip-message/response-codes.d.mts.map +1 -0
- package/dist/sip-message/response-codes.mjs +2 -0
- package/dist/sip-message/response-codes.mjs.map +1 -0
- package/dist/sip-message/sip-message.mjs +2 -0
- package/dist/sip-message/sip-message.mjs.map +1 -0
- package/dist/sip-message-B2D5MPBI.d.cts +2 -1
- package/dist/sip-message-B2D5MPBI.d.cts.map +1 -0
- package/dist/sip-message-PaPho4qU.d.mts +2 -1
- package/dist/sip-message-PaPho4qU.d.mts.map +1 -0
- package/dist/types-DOQ9wmX6.d.mts +2 -1
- package/dist/types-DOQ9wmX6.d.mts.map +1 -0
- package/dist/types-DZxCsbZE.d.cts +2 -1
- package/dist/types-DZxCsbZE.d.cts.map +1 -0
- package/dist/utils.d.cts +2 -1
- package/dist/utils.d.cts.map +1 -0
- package/dist/utils.d.mts +2 -1
- package/dist/utils.d.mts.map +1 -0
- package/dist/utils.mjs +2 -0
- package/dist/utils.mjs.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbound.mjs","names":[],"sources":["../../src/call-session/inbound.ts"],"sourcesContent":["import type Softphone from \"../index.js\";\nimport { type InboundMessage, OutboundMessage } from \"../sip-message/index.js\";\nimport { localKey, randomInt } from \"../utils.js\";\nimport CallSession from \"./index.js\";\n\nclass InboundCallSession extends CallSession {\n public constructor(softphone: Softphone, inviteMessage: InboundMessage) {\n super(softphone, inviteMessage);\n this.localPeer = inviteMessage.headers.To;\n this.remotePeer = inviteMessage.headers.From;\n // inbound call from call queue, invite message may not have body\n if (inviteMessage.body.length > 0) {\n this.remoteKey = inviteMessage.body.match(\n /AES_CM_128_HMAC_SHA1_80 inline:([\\w+/]+)/,\n )![1];\n }\n }\n\n public async answer() {\n const answerSDP = `\nv=0\no=- ${Date.now()} 0 IN IP4 ${this.softphone.client.localAddress}\ns=rc-softphone-ts\nc=IN IP4 ${this.softphone.client.localAddress}\nt=0 0\nm=audio ${randomInt()} RTP/SAVP ${this.softphone.codec.id} 101\na=rtpmap:${this.softphone.codec.id} ${this.softphone.codec.name}\na=rtpmap:101 telephone-event/8000\na=fmtp:101 0-15\na=sendrecv\na=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:${localKey}\n`.trim();\n this.sdp = answerSDP;\n const newMessage = new OutboundMessage(\n \"SIP/2.0 200 OK\",\n {\n Via: this.sipMessage.headers.Via,\n \"Call-ID\": this.sipMessage.getHeader(\"Call-ID\"),\n From: this.sipMessage.headers.From,\n To: this.sipMessage.headers.To,\n CSeq: this.sipMessage.headers.CSeq,\n Contact: `<sip:${this.softphone.sipInfo.username}@${this.softphone.client.localAddress}:${this.softphone.client.localPort};transport=TLS;ob>`,\n Allow:\n \"PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS\",\n Supported: \"replaces, 100rel, timer, norefersub\",\n \"Session-Expires\": \"14400;refresher=uac\",\n Require: \"timer\",\n \"Content-Type\": \"application/sdp\",\n },\n answerSDP,\n );\n const ackMessage = await this.softphone.send(newMessage, true);\n\n // for inbound call from call queue, ack message may HAVE body (while invite message has no body)\n if (ackMessage.body.length > 0) {\n this.remoteIP = ackMessage.body.match(/c=IN IP4 ([\\d.]+)/)![1];\n this.remotePort = parseInt(\n ackMessage.body.match(/m=audio (\\d+) /)![1],\n 10,\n );\n this.remoteKey = ackMessage.body.match(\n /AES_CM_128_HMAC_SHA1_80 inline:([\\w+/]+)/,\n )![1];\n }\n\n this.startLocalServices();\n }\n}\n\nexport default InboundCallSession;\n"],"mappings":";;;;;AAKA,IAAM,qBAAN,cAAiC,YAAY;CAC3C,YAAmB,WAAsB,eAA+B;AACtE,QAAM,WAAW,cAAc;AAC/B,OAAK,YAAY,cAAc,QAAQ;AACvC,OAAK,aAAa,cAAc,QAAQ;AAExC,MAAI,cAAc,KAAK,SAAS,EAC9B,MAAK,YAAY,cAAc,KAAK,MAClC,2CACD,CAAE;;CAIP,MAAa,SAAS;EACpB,MAAM,YAAY;;MAEhB,KAAK,KAAK,CAAC,YAAY,KAAK,UAAU,OAAO,aAAa;;WAErD,KAAK,UAAU,OAAO,aAAa;;UAEpC,WAAW,CAAC,YAAY,KAAK,UAAU,MAAM,GAAG;WAC/C,KAAK,UAAU,MAAM,GAAG,GAAG,KAAK,UAAU,MAAM,KAAK;;;;4CAIpB,SAAS;EACnD,MAAM;AACJ,OAAK,MAAM;EACX,MAAM,aAAa,IAAI,gBACrB,kBACA;GACE,KAAK,KAAK,WAAW,QAAQ;GAC7B,WAAW,KAAK,WAAW,UAAU,UAAU;GAC/C,MAAM,KAAK,WAAW,QAAQ;GAC9B,IAAI,KAAK,WAAW,QAAQ;GAC5B,MAAM,KAAK,WAAW,QAAQ;GAC9B,SAAS,QAAQ,KAAK,UAAU,QAAQ,SAAS,GAAG,KAAK,UAAU,OAAO,aAAa,GAAG,KAAK,UAAU,OAAO,UAAU;GAC1H,OACE;GACF,WAAW;GACX,mBAAmB;GACnB,SAAS;GACT,gBAAgB;GACjB,EACD,UACD;EACD,MAAM,aAAa,MAAM,KAAK,UAAU,KAAK,YAAY,KAAK;AAG9D,MAAI,WAAW,KAAK,SAAS,GAAG;AAC9B,QAAK,WAAW,WAAW,KAAK,MAAM,oBAAoB,CAAE;AAC5D,QAAK,aAAa,SAChB,WAAW,KAAK,MAAM,iBAAiB,CAAE,IACzC,GACD;AACD,QAAK,YAAY,WAAW,KAAK,MAC/B,2CACD,CAAE;;AAGL,OAAK,oBAAoB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/call-session/index.ts"],"sourcesContent":["import { Buffer } from \"node:buffer\";\nimport dgram from \"node:dgram\";\nimport EventEmitter from \"node:events\";\nimport waitFor from \"wait-for-async\";\nimport { RtpHeader, RtpPacket, SrtpSession } from \"werift-rtp\";\nimport DTMF from \"../dtmf.js\";\nimport type Softphone from \"../index.js\";\nimport {\n type InboundMessage,\n RequestMessage,\n ResponseMessage,\n} from \"../sip-message/index.js\";\nimport { branch, extractAddress, localKey, randomInt } from \"../utils.js\";\nimport Streamer from \"./streamer.js\";\n\ntype DtmfChar = (typeof DTMF.phoneChars)[number];\n\nconst isDtmfChar = (value: string): value is DtmfChar =>\n (DTMF.phoneChars as readonly string[]).includes(value);\n\nabstract class CallSession extends EventEmitter {\n public softphone: Softphone;\n public sipMessage: InboundMessage;\n public socket!: dgram.Socket;\n public localPeer!: string;\n public remotePeer!: string;\n public remoteIP!: string;\n public remotePort!: number;\n public disposed = false;\n public srtpSession!: SrtpSession;\n public encoder: { encode: (pcm: Buffer) => Buffer };\n public decoder: { decode: (audio: Buffer) => Buffer };\n public sdp!: string;\n\n // for audio streaming\n public ssrc = randomInt();\n public sequenceNumber = randomInt();\n public timestamp = randomInt();\n\n public constructor(softphone: Softphone, sipMessage: InboundMessage) {\n super();\n this.softphone = softphone;\n this.encoder = softphone.codec.createEncoder();\n this.decoder = softphone.codec.createDecoder();\n this.sipMessage = sipMessage;\n // inbound call from call queue, invite message may not have body\n if (this.sipMessage.body.length > 0) {\n this.remoteIP = this.sipMessage.body.match(/c=IN IP4 ([\\d.]+)/)![1];\n this.remotePort = parseInt(\n this.sipMessage.body.match(/m=audio (\\d+) /)![1],\n 10,\n );\n }\n }\n\n public set remoteKey(key: string) {\n const localKeyBuffer = Buffer.from(localKey, \"base64\");\n const remoteKeyBuffer = Buffer.from(key, \"base64\");\n this.srtpSession = new SrtpSession({\n profile: 0x0001,\n keys: {\n localMasterKey: localKeyBuffer.subarray(0, 16),\n localMasterSalt: localKeyBuffer.subarray(16, 30),\n remoteMasterKey: remoteKeyBuffer.subarray(0, 16),\n remoteMasterSalt: remoteKeyBuffer.subarray(16, 30),\n },\n });\n }\n\n public get callId() {\n return this.sipMessage.getHeader(\"Call-ID\");\n }\n\n public send(data: string | Buffer) {\n this.socket.send(data, this.remotePort, this.remoteIP);\n }\n\n public async hangup() {\n const requestMessage = new RequestMessage(\n `BYE sip:${this.softphone.sipInfo.domain} SIP/2.0`,\n {\n \"Call-ID\": this.callId,\n From: this.localPeer,\n To: this.remotePeer,\n Via: `SIP/2.0/TLS ${this.softphone.fakeDomain};branch=${branch()}`,\n },\n );\n await this.softphone.send(requestMessage);\n }\n\n public sendDTMF(char: DtmfChar) {\n const payloads = DTMF.charToPayloads(char);\n const timestamp = this.timestamp;\n let first = true;\n for (const payload of payloads) {\n const rtpHeader = new RtpHeader({\n version: 2,\n padding: false,\n paddingSize: 0,\n extension: false,\n marker: first,\n payloadOffset: 12,\n payloadType: 101,\n sequenceNumber: this.sequenceNumber,\n timestamp,\n ssrc: this.ssrc,\n csrcLength: 0,\n csrc: [],\n extensionProfile: 48862,\n extensionLength: undefined,\n extensions: [],\n });\n const rtpPacket = new RtpPacket(rtpHeader, payload);\n this.send(this.srtpSession.encrypt(rtpPacket.payload, rtpPacket.header));\n this.sequenceNumber = (this.sequenceNumber + 1) % 65536;\n first = false;\n }\n this.timestamp += 800;\n }\n\n public async sendDTMFs(s: string, delay = 500) {\n for (const c of s) {\n if (!isDtmfChar(c)) {\n throw new Error(`invalid phone char: ${c}`);\n }\n this.sendDTMF(c);\n await waitFor({ interval: delay });\n }\n }\n\n // buffer is the content of a audio file, it is supposed to be uncompressed PCM data\n // The audio should be playable by command: play -t raw -b 16 -r 16000 -e signed-integer test.wav\n public streamAudio(input: Buffer) {\n const streamer = new Streamer(this, input);\n streamer.start();\n return streamer;\n }\n\n // send a single rtp packet\n public sendPacket(rtpPacket: RtpPacket) {\n if (this.disposed) {\n return;\n }\n this.send(this.srtpSession.encrypt(rtpPacket.payload, rtpPacket.header));\n }\n\n protected startLocalServices() {\n this.socket = dgram.createSocket(\"udp4\");\n this.socket.on(\"message\", (message) => {\n const rtpPacket = RtpPacket.deSerialize(\n this.srtpSession.decrypt(message),\n );\n this.emit(\"rtpPacket\", rtpPacket);\n if (rtpPacket.header.payloadType === 101) {\n this.emit(\"dtmfPacket\", rtpPacket);\n const char = DTMF.payloadToChar(rtpPacket.payload);\n if (char) {\n this.emit(\"dtmf\", char);\n }\n } else if (rtpPacket.header.payloadType === this.softphone.codec.id) {\n if (\n rtpPacket.payload.length === 4 &&\n rtpPacket.payload[0] >= 0x00 &&\n rtpPacket.payload[0] < 0x0c &&\n rtpPacket.payload[1] === 0x8a &&\n rtpPacket.payload[2] === 0x03 &&\n rtpPacket.payload[3] === 0xc0\n ) {\n // special DTMF packet in audio format\n // first byte 0x00 to 0x0c means DTMF 0 to 9, *, #\n // we ignore it since DTMF is handled by `if (rtpPacket.header.payloadType === 101) {`\n return; // ignore it\n }\n try {\n rtpPacket.payload = this.decoder.decode(rtpPacket.payload);\n this.emit(\"audioPacket\", rtpPacket);\n } catch {\n console.error(\"Audio packet decode failed\", rtpPacket);\n }\n }\n });\n\n // as I tested, we can use a random port here and it still works\n // but it seems that in SDP we need to tell remote our local IP Address, not 127.0.0.1\n this.socket.bind(); // random port\n // send a message to remote server so that it knows where to reply\n this.send(\"hello\");\n\n const byeHandler = (inboundMessage: InboundMessage) => {\n if (inboundMessage.getHeader(\"Call-ID\") !== this.callId) {\n return;\n }\n if (inboundMessage.headers.CSeq.endsWith(\" BYE\")) {\n this.softphone.off(\"message\", byeHandler);\n this.dispose();\n }\n };\n this.softphone.on(\"message\", byeHandler);\n }\n\n protected dispose() {\n this.disposed = true;\n this.emit(\"disposed\");\n this.removeAllListeners();\n this.socket?.removeAllListeners();\n this.socket?.close();\n }\n\n public async transfer(transferTo: string) {\n const requestMessage = new RequestMessage(\n `REFER sip:${this.softphone.sipInfo.username}@${this.softphone.sipInfo.outboundProxy};transport=tls SIP/2.0`,\n {\n Via: `SIP/2.0/TLS ${this.softphone.client.localAddress}:${this.softphone.client.localPort};rport;branch=${branch()};alias`,\n \"Max-Forwards\": 70,\n From: this.localPeer,\n To: this.remotePeer,\n Contact: `<sip:${this.softphone.sipInfo.username}@${this.softphone.client.localAddress}:${this.softphone.client.localPort};transport=TLS;ob>`,\n \"Call-ID\": this.callId,\n Event: \"refer\",\n Expires: 600,\n Supported: \"replaces, 100rel, timer, norefersub\",\n Accept: \"message/sipfrag;version=2.0\",\n \"Allow-Events\": \"presence, message-summary, refer\",\n \"Refer-To\": `sip:${transferTo}@${this.softphone.sipInfo.domain}`,\n \"Referred-By\": `<sip:${this.softphone.sipInfo.username}@${this.softphone.sipInfo.domain}>`,\n },\n );\n await this.softphone.send(requestMessage);\n\n return new Promise<void>((resolve) => {\n const notifyHandler = (inboundMessage: InboundMessage) => {\n if (!inboundMessage.subject.startsWith(\"NOTIFY \")) {\n return;\n }\n const responseMessage = new ResponseMessage(inboundMessage, 200);\n this.softphone.send(responseMessage);\n if (inboundMessage.body.trim() === \"SIP/2.0 200 OK\") {\n this.softphone.off(\"message\", notifyHandler);\n resolve();\n }\n };\n this.softphone.on(\"message\", notifyHandler);\n });\n }\n\n public async toggleReceive(toReceive: boolean) {\n let newSDP = this.sdp;\n if (!toReceive) {\n newSDP = newSDP.replace(/a=sendrecv/, \"a=sendonly\");\n }\n const requestMessage = new RequestMessage(\n `INVITE ${extractAddress(this.remotePeer)} SIP/2.0`,\n {\n \"Call-Id\": this.callId,\n From: this.localPeer,\n To: this.remotePeer,\n Via: `SIP/2.0/TLS ${this.softphone.client.localAddress}:${this.softphone.client.localPort};rport;branch=${branch()};alias`,\n \"Content-Type\": \"application/sdp\",\n Contact: ` <sip:${this.softphone.sipInfo.username}@${this.softphone.client.localAddress}:${this.softphone.client.localPort};transport=TLS;ob>`,\n },\n newSDP,\n );\n const replyMessage = await this.softphone.send(requestMessage, true);\n const ackMessage = new RequestMessage(\n `ACK ${extractAddress(this.remotePeer)} SIP/2.0`,\n {\n \"Call-Id\": this.callId,\n From: this.localPeer,\n To: this.remotePeer,\n Via: replyMessage.headers.Via,\n CSeq: replyMessage.headers.CSeq.replace(\" INVITE\", \" ACK\"),\n },\n );\n await this.softphone.send(ackMessage);\n }\n\n public async hold() {\n return this.toggleReceive(false);\n }\n\n public async unhold() {\n return this.toggleReceive(true);\n }\n}\n\nexport default CallSession;\n"],"mappings":";;;;;;;;;;;;AAiBA,MAAM,cAAc,UACjB,KAAK,WAAiC,SAAS,MAAM;AAExD,IAAe,cAAf,cAAmC,aAAa;CAC9C;CACA;CACA;CACA;CACA;CACA;CACA;CACA,WAAkB;CAClB;CACA;CACA;CACA;CAGA,OAAc,WAAW;CACzB,iBAAwB,WAAW;CACnC,YAAmB,WAAW;CAE9B,YAAmB,WAAsB,YAA4B;AACnE,SAAO;AACP,OAAK,YAAY;AACjB,OAAK,UAAU,UAAU,MAAM,eAAe;AAC9C,OAAK,UAAU,UAAU,MAAM,eAAe;AAC9C,OAAK,aAAa;AAElB,MAAI,KAAK,WAAW,KAAK,SAAS,GAAG;AACnC,QAAK,WAAW,KAAK,WAAW,KAAK,MAAM,oBAAoB,CAAE;AACjE,QAAK,aAAa,SAChB,KAAK,WAAW,KAAK,MAAM,iBAAiB,CAAE,IAC9C,GACD;;;CAIL,IAAW,UAAU,KAAa;EAChC,MAAM,iBAAiB,OAAO,KAAK,UAAU,SAAS;EACtD,MAAM,kBAAkB,OAAO,KAAK,KAAK,SAAS;AAClD,OAAK,cAAc,IAAI,YAAY;GACjC,SAAS;GACT,MAAM;IACJ,gBAAgB,eAAe,SAAS,GAAG,GAAG;IAC9C,iBAAiB,eAAe,SAAS,IAAI,GAAG;IAChD,iBAAiB,gBAAgB,SAAS,GAAG,GAAG;IAChD,kBAAkB,gBAAgB,SAAS,IAAI,GAAG;IACnD;GACF,CAAC;;CAGJ,IAAW,SAAS;AAClB,SAAO,KAAK,WAAW,UAAU,UAAU;;CAG7C,KAAY,MAAuB;AACjC,OAAK,OAAO,KAAK,MAAM,KAAK,YAAY,KAAK,SAAS;;CAGxD,MAAa,SAAS;EACpB,MAAM,iBAAiB,IAAI,eACzB,WAAW,KAAK,UAAU,QAAQ,OAAO,WACzC;GACE,WAAW,KAAK;GAChB,MAAM,KAAK;GACX,IAAI,KAAK;GACT,KAAK,eAAe,KAAK,UAAU,WAAW,UAAU,QAAQ;GACjE,CACF;AACD,QAAM,KAAK,UAAU,KAAK,eAAe;;CAG3C,SAAgB,MAAgB;EAC9B,MAAM,WAAW,KAAK,eAAe,KAAK;EAC1C,MAAM,YAAY,KAAK;EACvB,IAAI,QAAQ;AACZ,OAAK,MAAM,WAAW,UAAU;GAkB9B,MAAM,YAAY,IAAI,UAAU,IAjBV,UAAU;IAC9B,SAAS;IACT,SAAS;IACT,aAAa;IACb,WAAW;IACX,QAAQ;IACR,eAAe;IACf,aAAa;IACb,gBAAgB,KAAK;IACrB;IACA,MAAM,KAAK;IACX,YAAY;IACZ,MAAM,EAAE;IACR,kBAAkB;IAClB,iBAAiB,KAAA;IACjB,YAAY,EAAE;IACf,CACwC,EAAE,QAAQ;AACnD,QAAK,KAAK,KAAK,YAAY,QAAQ,UAAU,SAAS,UAAU,OAAO,CAAC;AACxE,QAAK,kBAAkB,KAAK,iBAAiB,KAAK;AAClD,WAAQ;;AAEV,OAAK,aAAa;;CAGpB,MAAa,UAAU,GAAW,QAAQ,KAAK;AAC7C,OAAK,MAAM,KAAK,GAAG;AACjB,OAAI,CAAC,WAAW,EAAE,CAChB,OAAM,IAAI,MAAM,uBAAuB,IAAI;AAE7C,QAAK,SAAS,EAAE;AAChB,SAAM,QAAQ,EAAE,UAAU,OAAO,CAAC;;;CAMtC,YAAmB,OAAe;EAChC,MAAM,WAAW,IAAI,SAAS,MAAM,MAAM;AAC1C,WAAS,OAAO;AAChB,SAAO;;CAIT,WAAkB,WAAsB;AACtC,MAAI,KAAK,SACP;AAEF,OAAK,KAAK,KAAK,YAAY,QAAQ,UAAU,SAAS,UAAU,OAAO,CAAC;;CAG1E,qBAA+B;AAC7B,OAAK,SAAS,MAAM,aAAa,OAAO;AACxC,OAAK,OAAO,GAAG,YAAY,YAAY;GACrC,MAAM,YAAY,UAAU,YAC1B,KAAK,YAAY,QAAQ,QAAQ,CAClC;AACD,QAAK,KAAK,aAAa,UAAU;AACjC,OAAI,UAAU,OAAO,gBAAgB,KAAK;AACxC,SAAK,KAAK,cAAc,UAAU;IAClC,MAAM,OAAO,KAAK,cAAc,UAAU,QAAQ;AAClD,QAAI,KACF,MAAK,KAAK,QAAQ,KAAK;cAEhB,UAAU,OAAO,gBAAgB,KAAK,UAAU,MAAM,IAAI;AACnE,QACE,UAAU,QAAQ,WAAW,KAC7B,UAAU,QAAQ,MAAM,KACxB,UAAU,QAAQ,KAAK,MACvB,UAAU,QAAQ,OAAO,OACzB,UAAU,QAAQ,OAAO,KACzB,UAAU,QAAQ,OAAO,IAKzB;AAEF,QAAI;AACF,eAAU,UAAU,KAAK,QAAQ,OAAO,UAAU,QAAQ;AAC1D,UAAK,KAAK,eAAe,UAAU;YAC7B;AACN,aAAQ,MAAM,8BAA8B,UAAU;;;IAG1D;AAIF,OAAK,OAAO,MAAM;AAElB,OAAK,KAAK,QAAQ;EAElB,MAAM,cAAc,mBAAmC;AACrD,OAAI,eAAe,UAAU,UAAU,KAAK,KAAK,OAC/C;AAEF,OAAI,eAAe,QAAQ,KAAK,SAAS,OAAO,EAAE;AAChD,SAAK,UAAU,IAAI,WAAW,WAAW;AACzC,SAAK,SAAS;;;AAGlB,OAAK,UAAU,GAAG,WAAW,WAAW;;CAG1C,UAAoB;AAClB,OAAK,WAAW;AAChB,OAAK,KAAK,WAAW;AACrB,OAAK,oBAAoB;AACzB,OAAK,QAAQ,oBAAoB;AACjC,OAAK,QAAQ,OAAO;;CAGtB,MAAa,SAAS,YAAoB;EACxC,MAAM,iBAAiB,IAAI,eACzB,aAAa,KAAK,UAAU,QAAQ,SAAS,GAAG,KAAK,UAAU,QAAQ,cAAc,yBACrF;GACE,KAAK,eAAe,KAAK,UAAU,OAAO,aAAa,GAAG,KAAK,UAAU,OAAO,UAAU,gBAAgB,QAAQ,CAAC;GACnH,gBAAgB;GAChB,MAAM,KAAK;GACX,IAAI,KAAK;GACT,SAAS,QAAQ,KAAK,UAAU,QAAQ,SAAS,GAAG,KAAK,UAAU,OAAO,aAAa,GAAG,KAAK,UAAU,OAAO,UAAU;GAC1H,WAAW,KAAK;GAChB,OAAO;GACP,SAAS;GACT,WAAW;GACX,QAAQ;GACR,gBAAgB;GAChB,YAAY,OAAO,WAAW,GAAG,KAAK,UAAU,QAAQ;GACxD,eAAe,QAAQ,KAAK,UAAU,QAAQ,SAAS,GAAG,KAAK,UAAU,QAAQ,OAAO;GACzF,CACF;AACD,QAAM,KAAK,UAAU,KAAK,eAAe;AAEzC,SAAO,IAAI,SAAe,YAAY;GACpC,MAAM,iBAAiB,mBAAmC;AACxD,QAAI,CAAC,eAAe,QAAQ,WAAW,UAAU,CAC/C;IAEF,MAAM,kBAAkB,IAAI,gBAAgB,gBAAgB,IAAI;AAChE,SAAK,UAAU,KAAK,gBAAgB;AACpC,QAAI,eAAe,KAAK,MAAM,KAAK,kBAAkB;AACnD,UAAK,UAAU,IAAI,WAAW,cAAc;AAC5C,cAAS;;;AAGb,QAAK,UAAU,GAAG,WAAW,cAAc;IAC3C;;CAGJ,MAAa,cAAc,WAAoB;EAC7C,IAAI,SAAS,KAAK;AAClB,MAAI,CAAC,UACH,UAAS,OAAO,QAAQ,cAAc,aAAa;EAErD,MAAM,iBAAiB,IAAI,eACzB,UAAU,eAAe,KAAK,WAAW,CAAC,WAC1C;GACE,WAAW,KAAK;GAChB,MAAM,KAAK;GACX,IAAI,KAAK;GACT,KAAK,eAAe,KAAK,UAAU,OAAO,aAAa,GAAG,KAAK,UAAU,OAAO,UAAU,gBAAgB,QAAQ,CAAC;GACnH,gBAAgB;GAChB,SAAS,SAAS,KAAK,UAAU,QAAQ,SAAS,GAAG,KAAK,UAAU,OAAO,aAAa,GAAG,KAAK,UAAU,OAAO,UAAU;GAC5H,EACD,OACD;EACD,MAAM,eAAe,MAAM,KAAK,UAAU,KAAK,gBAAgB,KAAK;EACpE,MAAM,aAAa,IAAI,eACrB,OAAO,eAAe,KAAK,WAAW,CAAC,WACvC;GACE,WAAW,KAAK;GAChB,MAAM,KAAK;GACX,IAAI,KAAK;GACT,KAAK,aAAa,QAAQ;GAC1B,MAAM,aAAa,QAAQ,KAAK,QAAQ,WAAW,OAAO;GAC3D,CACF;AACD,QAAM,KAAK,UAAU,KAAK,WAAW;;CAGvC,MAAa,OAAO;AAClB,SAAO,KAAK,cAAc,MAAM;;CAGlC,MAAa,SAAS;AACpB,SAAO,KAAK,cAAc,KAAK"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound.mjs","names":[],"sources":["../../src/call-session/outbound.ts"],"sourcesContent":["import type Softphone from \"../index.js\";\nimport { type InboundMessage, RequestMessage } from \"../sip-message/index.js\";\nimport { extractAddress, withoutTag } from \"../utils.js\";\nimport CallSession from \"./index.js\";\n\nclass OutboundCallSession extends CallSession {\n public constructor(softphone: Softphone, answerMessage: InboundMessage) {\n super(softphone, answerMessage);\n this.localPeer = answerMessage.headers.From;\n this.remotePeer = answerMessage.headers.To;\n this.remoteKey = answerMessage.body.match(\n /AES_CM_128_HMAC_SHA1_80 inline:([\\w+/]+)/,\n )![1];\n this.init();\n }\n\n public init() {\n // wait for user to answer the call\n const answerHandler = (message: InboundMessage) => {\n if (message.headers.CSeq !== this.sipMessage.headers.CSeq) {\n return;\n }\n if (message.subject.startsWith(\"SIP/2.0 486\")) {\n this.softphone.off(\"message\", answerHandler);\n this.emit(\"busy\");\n this.dispose();\n return;\n }\n if (message.subject.startsWith(\"SIP/2.0 200\")) {\n this.softphone.off(\"message\", answerHandler);\n this.emit(\"answered\");\n\n const ackMessage = new RequestMessage(\n `ACK ${extractAddress(this.remotePeer)} SIP/2.0`,\n {\n \"Call-ID\": this.callId,\n From: this.localPeer,\n To: this.remotePeer,\n Via: this.sipMessage.headers.Via,\n CSeq: this.sipMessage.headers.CSeq.replace(\" INVITE\", \" ACK\"),\n },\n );\n this.softphone.send(ackMessage);\n }\n };\n this.softphone.on(\"message\", answerHandler);\n this.once(\"answered\", () => this.startLocalServices());\n }\n\n public async cancel() {\n const requestMessage = new RequestMessage(\n `CANCEL ${extractAddress(this.remotePeer)} SIP/2.0`,\n {\n \"Call-ID\": this.callId,\n From: this.localPeer,\n To: withoutTag(this.remotePeer),\n Via: this.sipMessage.headers.Via,\n CSeq: this.sipMessage.headers.CSeq.replace(\" INVITE\", \" CANCEL\"),\n },\n );\n await this.softphone.send(requestMessage);\n }\n\n public get sessionId() {\n const header = this.sipMessage.headers[\"p-rc-api-ids\"];\n const match = header.match(/party-id=([^;]+);session-id=([^;]+)/)!;\n return match[2];\n }\n public get partyId() {\n const header = this.sipMessage.headers[\"p-rc-api-ids\"];\n const match = header.match(/party-id=([^;]+);session-id=([^;]+)/)!;\n return match[1];\n }\n}\n\nexport default OutboundCallSession;\n"],"mappings":";;;;;AAKA,IAAM,sBAAN,cAAkC,YAAY;CAC5C,YAAmB,WAAsB,eAA+B;AACtE,QAAM,WAAW,cAAc;AAC/B,OAAK,YAAY,cAAc,QAAQ;AACvC,OAAK,aAAa,cAAc,QAAQ;AACxC,OAAK,YAAY,cAAc,KAAK,MAClC,2CACD,CAAE;AACH,OAAK,MAAM;;CAGb,OAAc;EAEZ,MAAM,iBAAiB,YAA4B;AACjD,OAAI,QAAQ,QAAQ,SAAS,KAAK,WAAW,QAAQ,KACnD;AAEF,OAAI,QAAQ,QAAQ,WAAW,cAAc,EAAE;AAC7C,SAAK,UAAU,IAAI,WAAW,cAAc;AAC5C,SAAK,KAAK,OAAO;AACjB,SAAK,SAAS;AACd;;AAEF,OAAI,QAAQ,QAAQ,WAAW,cAAc,EAAE;AAC7C,SAAK,UAAU,IAAI,WAAW,cAAc;AAC5C,SAAK,KAAK,WAAW;IAErB,MAAM,aAAa,IAAI,eACrB,OAAO,eAAe,KAAK,WAAW,CAAC,WACvC;KACE,WAAW,KAAK;KAChB,MAAM,KAAK;KACX,IAAI,KAAK;KACT,KAAK,KAAK,WAAW,QAAQ;KAC7B,MAAM,KAAK,WAAW,QAAQ,KAAK,QAAQ,WAAW,OAAO;KAC9D,CACF;AACD,SAAK,UAAU,KAAK,WAAW;;;AAGnC,OAAK,UAAU,GAAG,WAAW,cAAc;AAC3C,OAAK,KAAK,kBAAkB,KAAK,oBAAoB,CAAC;;CAGxD,MAAa,SAAS;EACpB,MAAM,iBAAiB,IAAI,eACzB,UAAU,eAAe,KAAK,WAAW,CAAC,WAC1C;GACE,WAAW,KAAK;GAChB,MAAM,KAAK;GACX,IAAI,WAAW,KAAK,WAAW;GAC/B,KAAK,KAAK,WAAW,QAAQ;GAC7B,MAAM,KAAK,WAAW,QAAQ,KAAK,QAAQ,WAAW,UAAU;GACjE,CACF;AACD,QAAM,KAAK,UAAU,KAAK,eAAe;;CAG3C,IAAW,YAAY;AAGrB,SAFe,KAAK,WAAW,QAAQ,gBAClB,MAAM,sCACf,CAAC;;CAEf,IAAW,UAAU;AAGnB,SAFe,KAAK,WAAW,QAAQ,gBAClB,MAAM,sCACf,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streamer.mjs","names":[],"sources":["../../src/call-session/streamer.ts"],"sourcesContent":["import { Buffer } from \"node:buffer\";\nimport EventEmitter from \"node:events\";\n\nimport { RtpHeader, RtpPacket } from \"werift-rtp\";\n\nimport type CallSession from \"./index.js\";\n\nclass Streamer extends EventEmitter {\n public paused = false;\n private callSession: CallSession;\n private buffer: Buffer;\n private originalBuffer: Buffer;\n\n public constructor(callSession: CallSession, buffer: Buffer) {\n super();\n this.callSession = callSession;\n this.buffer = buffer;\n this.originalBuffer = buffer;\n }\n\n public start() {\n this.buffer = this.originalBuffer;\n this.paused = false;\n this.sendPacket();\n }\n\n public stop() {\n this.buffer = Buffer.alloc(0);\n }\n\n public pause() {\n this.paused = true;\n }\n\n public resume() {\n this.paused = false;\n this.sendPacket();\n }\n\n public get finished() {\n return (\n this.callSession.disposed ||\n this.buffer.length < this.callSession.softphone.codec.packetSize\n );\n }\n\n private sendPacket() {\n if (!this.paused && !this.finished) {\n const temp = this.callSession.encoder.encode(\n this.buffer.subarray(0, this.callSession.softphone.codec.packetSize),\n );\n const rtpPacket = new RtpPacket(\n new RtpHeader({\n version: 2,\n padding: false,\n paddingSize: 0,\n extension: false,\n marker: false,\n payloadOffset: 12,\n payloadType: this.callSession.softphone.codec.id,\n sequenceNumber: this.callSession.sequenceNumber,\n timestamp: this.callSession.timestamp,\n ssrc: this.callSession.ssrc,\n csrcLength: 0,\n csrc: [],\n extensionProfile: 48862,\n extensionLength: undefined,\n extensions: [],\n }),\n temp,\n );\n this.callSession.send(\n this.callSession.srtpSession.encrypt(\n rtpPacket.payload,\n rtpPacket.header,\n ),\n );\n this.callSession.sequenceNumber += 1;\n if (this.callSession.sequenceNumber > 65535) {\n this.callSession.sequenceNumber = 0;\n }\n this.callSession.timestamp +=\n this.callSession.softphone.codec.timestampInterval;\n this.buffer = this.buffer.subarray(\n this.callSession.softphone.codec.packetSize,\n );\n if (this.finished) {\n this.emit(\"finished\");\n } else {\n setTimeout(() => this.sendPacket(), 20);\n }\n }\n }\n}\n\nexport default Streamer;\n"],"mappings":";;;;AAOA,IAAM,WAAN,cAAuB,aAAa;CAClC,SAAgB;CAChB;CACA;CACA;CAEA,YAAmB,aAA0B,QAAgB;AAC3D,SAAO;AACP,OAAK,cAAc;AACnB,OAAK,SAAS;AACd,OAAK,iBAAiB;;CAGxB,QAAe;AACb,OAAK,SAAS,KAAK;AACnB,OAAK,SAAS;AACd,OAAK,YAAY;;CAGnB,OAAc;AACZ,OAAK,SAAS,OAAO,MAAM,EAAE;;CAG/B,QAAe;AACb,OAAK,SAAS;;CAGhB,SAAgB;AACd,OAAK,SAAS;AACd,OAAK,YAAY;;CAGnB,IAAW,WAAW;AACpB,SACE,KAAK,YAAY,YACjB,KAAK,OAAO,SAAS,KAAK,YAAY,UAAU,MAAM;;CAI1D,aAAqB;AACnB,MAAI,CAAC,KAAK,UAAU,CAAC,KAAK,UAAU;GAClC,MAAM,OAAO,KAAK,YAAY,QAAQ,OACpC,KAAK,OAAO,SAAS,GAAG,KAAK,YAAY,UAAU,MAAM,WAAW,CACrE;GACD,MAAM,YAAY,IAAI,UACpB,IAAI,UAAU;IACZ,SAAS;IACT,SAAS;IACT,aAAa;IACb,WAAW;IACX,QAAQ;IACR,eAAe;IACf,aAAa,KAAK,YAAY,UAAU,MAAM;IAC9C,gBAAgB,KAAK,YAAY;IACjC,WAAW,KAAK,YAAY;IAC5B,MAAM,KAAK,YAAY;IACvB,YAAY;IACZ,MAAM,EAAE;IACR,kBAAkB;IAClB,iBAAiB,KAAA;IACjB,YAAY,EAAE;IACf,CAAC,EACF,KACD;AACD,QAAK,YAAY,KACf,KAAK,YAAY,YAAY,QAC3B,UAAU,SACV,UAAU,OACX,CACF;AACD,QAAK,YAAY,kBAAkB;AACnC,OAAI,KAAK,YAAY,iBAAiB,MACpC,MAAK,YAAY,iBAAiB;AAEpC,QAAK,YAAY,aACf,KAAK,YAAY,UAAU,MAAM;AACnC,QAAK,SAAS,KAAK,OAAO,SACxB,KAAK,YAAY,UAAU,MAAM,WAClC;AACD,OAAI,KAAK,SACP,MAAK,KAAK,WAAW;OAErB,kBAAiB,KAAK,YAAY,EAAE,GAAG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codec-Bh7v8J-S.d.mts","names":[],"sources":["../src/codec.ts"],"mappings":";;;cAGM,KAAA;EACJ,EAAA;EACA,IAAA;EACA,UAAA;EACA,iBAAA;EACA,aAAA;IAAuB,MAAA,GAAS,GAAA,EAAK,MAAA,KAAW,MAAA;EAAA;EAChD,aAAA;IAAuB,MAAA,GAAS,KAAA,EAAO,MAAA,KAAW,MAAA;EAAA;cACtC,IAAA;AAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codec-C-VrtVkq.d.cts","names":[],"sources":["../src/codec.ts"],"mappings":";;;cAGM,KAAA;EACJ,EAAA;EACA,IAAA;EACA,UAAA;EACA,iBAAA;EACA,aAAA;IAAuB,MAAA,GAAS,GAAA,EAAK,MAAA,KAAW,MAAA;EAAA;EAChD,aAAA;IAAuB,MAAA,GAAS,KAAA,EAAO,MAAA,KAAW,MAAA;EAAA;cACtC,IAAA;AAAA"}
|
package/dist/codec.mjs
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codec.mjs","names":[],"sources":["../src/codec.ts"],"sourcesContent":["import { Buffer } from \"node:buffer\";\nimport { Decoder, Encoder } from \"@evan/opus\";\n\nclass Codec {\n id: number;\n name: \"OPUS/16000\" | \"OPUS/48000/2\" | \"PCMU/8000\";\n packetSize: number;\n timestampInterval: number;\n createEncoder: () => { encode: (pcm: Buffer) => Buffer };\n createDecoder: () => { decode: (audio: Buffer) => Buffer };\n constructor(name: \"OPUS/16000\" | \"OPUS/48000/2\" | \"PCMU/8000\") {\n this.name = name;\n switch (name) {\n case \"OPUS/16000\": {\n this.createEncoder = () => {\n const encoder = new Encoder({ channels: 1, sample_rate: 16000 });\n return { encode: (pcm: Buffer) => Buffer.from(encoder.encode(pcm)) };\n };\n this.createDecoder = () => {\n const decoder = new Decoder({ channels: 1, sample_rate: 16000 });\n return {\n decode: (opus: Buffer) => Buffer.from(decoder.decode(opus)),\n };\n };\n this.id = 109;\n this.packetSize = 640;\n this.timestampInterval = 320;\n break;\n }\n case \"OPUS/48000/2\": {\n this.createEncoder = () => {\n const encoder = new Encoder({ channels: 2, sample_rate: 48000 });\n return { encode: (pcm: Buffer) => Buffer.from(encoder.encode(pcm)) };\n };\n this.createDecoder = () => {\n const decoder = new Decoder({ channels: 2, sample_rate: 48000 });\n return {\n decode: (opus: Buffer) => Buffer.from(decoder.decode(opus)),\n };\n };\n this.id = 111;\n this.packetSize = 3840;\n this.timestampInterval = 960;\n break;\n }\n case \"PCMU/8000\": {\n this.createEncoder = () => {\n return { encode: (pcm: Buffer) => pcm };\n };\n this.createDecoder = () => {\n return { decode: (audio: Buffer) => audio };\n };\n this.id = 0;\n this.packetSize = 160;\n this.timestampInterval = 160;\n break;\n }\n default: {\n throw new Error(`unsupported codec: ${name}`);\n }\n }\n }\n}\n\nexport default Codec;\n"],"mappings":";;;AAGA,IAAM,QAAN,MAAY;CACV;CACA;CACA;CACA;CACA;CACA;CACA,YAAY,MAAmD;AAC7D,OAAK,OAAO;AACZ,UAAQ,MAAR;GACE,KAAK;AACH,SAAK,sBAAsB;KACzB,MAAM,UAAU,IAAI,QAAQ;MAAE,UAAU;MAAG,aAAa;MAAO,CAAC;AAChE,YAAO,EAAE,SAAS,QAAgB,OAAO,KAAK,QAAQ,OAAO,IAAI,CAAC,EAAE;;AAEtE,SAAK,sBAAsB;KACzB,MAAM,UAAU,IAAI,QAAQ;MAAE,UAAU;MAAG,aAAa;MAAO,CAAC;AAChE,YAAO,EACL,SAAS,SAAiB,OAAO,KAAK,QAAQ,OAAO,KAAK,CAAC,EAC5D;;AAEH,SAAK,KAAK;AACV,SAAK,aAAa;AAClB,SAAK,oBAAoB;AACzB;GAEF,KAAK;AACH,SAAK,sBAAsB;KACzB,MAAM,UAAU,IAAI,QAAQ;MAAE,UAAU;MAAG,aAAa;MAAO,CAAC;AAChE,YAAO,EAAE,SAAS,QAAgB,OAAO,KAAK,QAAQ,OAAO,IAAI,CAAC,EAAE;;AAEtE,SAAK,sBAAsB;KACzB,MAAM,UAAU,IAAI,QAAQ;MAAE,UAAU;MAAG,aAAa;MAAO,CAAC;AAChE,YAAO,EACL,SAAS,SAAiB,OAAO,KAAK,QAAQ,OAAO,KAAK,CAAC,EAC5D;;AAEH,SAAK,KAAK;AACV,SAAK,aAAa;AAClB,SAAK,oBAAoB;AACzB;GAEF,KAAK;AACH,SAAK,sBAAsB;AACzB,YAAO,EAAE,SAAS,QAAgB,KAAK;;AAEzC,SAAK,sBAAsB;AACzB,YAAO,EAAE,SAAS,UAAkB,OAAO;;AAE7C,SAAK,KAAK;AACV,SAAK,aAAa;AAClB,SAAK,oBAAoB;AACzB;GAEF,QACE,OAAM,IAAI,MAAM,sBAAsB,OAAO"}
|
package/dist/dtmf-B13Fz2VR.d.mts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dtmf-B13Fz2VR.d.mts","names":[],"sources":["../src/dtmf.ts"],"mappings":";;;cAoBM,IAAA;;gCAEuB,MAAA,CAAA,WAAA;yBAYJ,MAAA;AAAA"}
|
package/dist/dtmf-DcQ-5vSG.d.cts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dtmf-DcQ-5vSG.d.cts","names":[],"sources":["../src/dtmf.ts"],"mappings":";;;cAoBM,IAAA;;gCAEuB,MAAA,CAAA,WAAA;yBAYJ,MAAA;AAAA"}
|
package/dist/dtmf.mjs
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dtmf.mjs","names":[],"sources":["../src/dtmf.ts"],"sourcesContent":["import { Buffer } from \"node:buffer\";\n\nconst phoneChars = [\n \"0\",\n \"1\",\n \"2\",\n \"3\",\n \"4\",\n \"5\",\n \"6\",\n \"7\",\n \"8\",\n \"9\",\n \"*\",\n \"#\",\n] as const;\nconst payloads = [\n 0x00060000, 0x000600a0, 0x00060140, 0x00860320, 0x00860320, 0x00860320,\n];\n\nconst DTMF = {\n phoneChars,\n charToPayloads(char: string) {\n const index = phoneChars.indexOf(char[0] as (typeof phoneChars)[number]);\n if (index === -1) {\n throw new Error(\"invalid phone char\");\n }\n return payloads.map((payload) => {\n const temp = payload + index * 0x01000000;\n const buffer = Buffer.alloc(4);\n buffer.writeIntBE(temp, 0, 4);\n return buffer;\n });\n },\n payloadToChar(payload: Buffer) {\n const intBE = payload.readIntBE(0, 4);\n const index = (intBE - 0x00060000) / 0x01000000;\n return phoneChars[index];\n },\n};\n\nexport default DTMF;\n"],"mappings":";;AAEA,MAAM,aAAa;CACjB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AACD,MAAM,WAAW;CACf;CAAY;CAAY;CAAY;CAAY;CAAY;CAC7D;AAED,MAAM,OAAO;CACX;CACA,eAAe,MAAc;EAC3B,MAAM,QAAQ,WAAW,QAAQ,KAAK,GAAkC;AACxE,MAAI,UAAU,GACZ,OAAM,IAAI,MAAM,qBAAqB;AAEvC,SAAO,SAAS,KAAK,YAAY;GAC/B,MAAM,OAAO,UAAU,QAAQ;GAC/B,MAAM,SAAS,OAAO,MAAM,EAAE;AAC9B,UAAO,WAAW,MAAM,GAAG,EAAE;AAC7B,UAAO;IACP;;CAEJ,cAAc,SAAiB;AAG7B,SAAO,YAFO,QAAQ,UAAU,GAAG,EACf,GAAG,UAAc;;CAGxC"}
|
|
@@ -100,4 +100,5 @@ declare class InboundCallSession extends CallSession {
|
|
|
100
100
|
answer(): Promise<void>;
|
|
101
101
|
}
|
|
102
102
|
//#endregion
|
|
103
|
-
export { Streamer as a, CallSession as i, Softphone as n, OutboundCallSession as r, InboundCallSession as t };
|
|
103
|
+
export { Streamer as a, CallSession as i, Softphone as n, OutboundCallSession as r, InboundCallSession as t };
|
|
104
|
+
//# sourceMappingURL=inbound--wGoGqLS.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbound--wGoGqLS.d.mts","names":[],"sources":["../src/call-session/streamer.ts","../src/call-session/index.ts","../src/call-session/outbound.ts","../src/index.ts","../src/call-session/inbound.ts"],"mappings":";;;;;;;;;;;;cAOM,QAAA,SAAiB,YAAA;EACd,MAAA;EAAA,QACC,WAAA;EAAA,QACA,MAAA;EAAA,QACA,cAAA;cAEW,WAAA,EAAa,WAAA,EAAa,MAAA,EAAQ,MAAA;EAO9C,KAAA,CAAA;EAMA,IAAA,CAAA;EAIA,KAAA,CAAA;EAIA,MAAA,CAAA;EAAA,IAKI,QAAA,CAAA;EAAA,QAOH,UAAA;AAAA;;;KC/BL,QAAA,WAAmB,IAAA,CAAK,UAAA;AAAA,uBAKd,WAAA,SAAoB,YAAA;EAC1B,SAAA,EAAW,SAAA;EACX,UAAA,EAAY,cAAA;EACZ,MAAA,EAAS,KAAA,CAAM,MAAA;EACf,SAAA;EACA,UAAA;EACA,QAAA;EACA,UAAA;EACA,QAAA;EACA,WAAA,EAAc,WAAA;EACd,OAAA;IAAW,MAAA,GAAS,GAAA,EAAK,MAAA,KAAW,MAAA;EAAA;EACpC,OAAA;IAAW,MAAA,GAAS,KAAA,EAAO,MAAA,KAAW,MAAA;EAAA;EACtC,GAAA;EAGA,IAAA;EACA,cAAA;EACA,SAAA;cAEY,SAAA,EAAW,SAAA,EAAW,UAAA,EAAY,cAAA;EAAA,IAgB1C,SAAA,CAAU,GAAA;EAAA,IAcV,MAAA,CAAA;EAIJ,IAAA,CAAK,IAAA,WAAe,MAAA;EAId,MAAA,CAAA,GAAM,OAAA;EAaZ,QAAA,CAAS,IAAA,EAAM,QAAA;EA8BT,SAAA,CAAU,CAAA,UAAW,KAAA,YAAW,OAAA;EAYtC,WAAA,CAAY,KAAA,EAAO,MAAA,GAAM,QAAA;EAOzB,UAAA,CAAW,SAAA,EAAW,SAAA;EAAA,UAOnB,kBAAA,CAAA;EAAA,UAsDA,OAAA,CAAA;EAQG,QAAA,CAAS,UAAA,WAAkB,OAAA;EAqC3B,aAAA,CAAc,SAAA,YAAkB,OAAA;EA+BhC,IAAA,CAAA,GAAI,OAAA;EAIJ,MAAA,CAAA,GAAM,OAAA;AAAA;;;cCnRf,mBAAA,SAA4B,WAAA;cACb,SAAA,EAAW,SAAA,EAAW,aAAA,EAAe,cAAA;EAUjD,IAAA,CAAA;EAiCM,MAAA,CAAA,GAAM,OAAA;EAAA,IAcR,SAAA,CAAA;EAAA,IAKA,OAAA,CAAA;AAAA;;;cC7CP,SAAA,SAAkB,YAAA;EACf,OAAA,EAAS,gBAAA;EACT,MAAA,EAAQ,SAAA;EACR,KAAA,EAAO,KAAA;EAEP,UAAA;EACA,SAAA;EAAA,QAEC,cAAA;EAAA,QACA,SAAA;cAEW,OAAA,EAAS,gBAAA;EAAA,QA+CpB,UAAA;EAAA,QACA,cAAA;EAEK,QAAA,CAAA,GAAQ,OAAA;EAuEd,eAAA,CAAA;EAWA,MAAA,CAAA;EAOA,IAAA,CACL,OAAA,EAAS,eAAA,EACT,YAAA,UACC,OAAA,CAAQ,cAAA;EACJ,IAAA,CACL,OAAA,EAAS,eAAA,EACT,YAAA,WACC,OAAA;EAyBU,MAAA,CAAO,aAAA,EAAe,cAAA,GAAc,OAAA,CAAA,kBAAA;EAOpC,OAAA,CAAQ,aAAA,EAAe,cAAA,GAAc,OAAA;EAKrC,IAAA,CAAK,MAAA,WAAc,OAAA,CAAA,mBAAA;AAAA;;;cCpN5B,kBAAA,SAA2B,WAAA;cACZ,SAAA,EAAW,SAAA,EAAW,aAAA,EAAe,cAAA;EAY3C,MAAA,CAAA,GAAM,OAAA;AAAA"}
|
|
@@ -100,4 +100,5 @@ declare class InboundCallSession extends CallSession {
|
|
|
100
100
|
answer(): Promise<void>;
|
|
101
101
|
}
|
|
102
102
|
//#endregion
|
|
103
|
-
export { Streamer as a, CallSession as i, Softphone as n, OutboundCallSession as r, InboundCallSession as t };
|
|
103
|
+
export { Streamer as a, CallSession as i, Softphone as n, OutboundCallSession as r, InboundCallSession as t };
|
|
104
|
+
//# sourceMappingURL=inbound-DquvTSj1.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbound-DquvTSj1.d.cts","names":[],"sources":["../src/call-session/streamer.ts","../src/call-session/index.ts","../src/call-session/outbound.ts","../src/index.ts","../src/call-session/inbound.ts"],"mappings":";;;;;;;;;;;;cAOM,QAAA,SAAiB,YAAA;EACd,MAAA;EAAA,QACC,WAAA;EAAA,QACA,MAAA;EAAA,QACA,cAAA;cAEW,WAAA,EAAa,WAAA,EAAa,MAAA,EAAQ,MAAA;EAO9C,KAAA,CAAA;EAMA,IAAA,CAAA;EAIA,KAAA,CAAA;EAIA,MAAA,CAAA;EAAA,IAKI,QAAA,CAAA;EAAA,QAOH,UAAA;AAAA;;;KC/BL,QAAA,WAAmB,IAAA,CAAK,UAAA;AAAA,uBAKd,WAAA,SAAoB,YAAA;EAC1B,SAAA,EAAW,SAAA;EACX,UAAA,EAAY,cAAA;EACZ,MAAA,EAAS,KAAA,CAAM,MAAA;EACf,SAAA;EACA,UAAA;EACA,QAAA;EACA,UAAA;EACA,QAAA;EACA,WAAA,EAAc,WAAA;EACd,OAAA;IAAW,MAAA,GAAS,GAAA,EAAK,MAAA,KAAW,MAAA;EAAA;EACpC,OAAA;IAAW,MAAA,GAAS,KAAA,EAAO,MAAA,KAAW,MAAA;EAAA;EACtC,GAAA;EAGA,IAAA;EACA,cAAA;EACA,SAAA;cAEY,SAAA,EAAW,SAAA,EAAW,UAAA,EAAY,cAAA;EAAA,IAgB1C,SAAA,CAAU,GAAA;EAAA,IAcV,MAAA,CAAA;EAIJ,IAAA,CAAK,IAAA,WAAe,MAAA;EAId,MAAA,CAAA,GAAM,OAAA;EAaZ,QAAA,CAAS,IAAA,EAAM,QAAA;EA8BT,SAAA,CAAU,CAAA,UAAW,KAAA,YAAW,OAAA;EAYtC,WAAA,CAAY,KAAA,EAAO,MAAA,GAAM,QAAA;EAOzB,UAAA,CAAW,SAAA,EAAW,SAAA;EAAA,UAOnB,kBAAA,CAAA;EAAA,UAsDA,OAAA,CAAA;EAQG,QAAA,CAAS,UAAA,WAAkB,OAAA;EAqC3B,aAAA,CAAc,SAAA,YAAkB,OAAA;EA+BhC,IAAA,CAAA,GAAI,OAAA;EAIJ,MAAA,CAAA,GAAM,OAAA;AAAA;;;cCnRf,mBAAA,SAA4B,WAAA;cACb,SAAA,EAAW,SAAA,EAAW,aAAA,EAAe,cAAA;EAUjD,IAAA,CAAA;EAiCM,MAAA,CAAA,GAAM,OAAA;EAAA,IAcR,SAAA,CAAA;EAAA,IAKA,OAAA,CAAA;AAAA;;;cC7CP,SAAA,SAAkB,YAAA;EACf,OAAA,EAAS,gBAAA;EACT,MAAA,EAAQ,SAAA;EACR,KAAA,EAAO,KAAA;EAEP,UAAA;EACA,SAAA;EAAA,QAEC,cAAA;EAAA,QACA,SAAA;cAEW,OAAA,EAAS,gBAAA;EAAA,QA+CpB,UAAA;EAAA,QACA,cAAA;EAEK,QAAA,CAAA,GAAQ,OAAA;EAuEd,eAAA,CAAA;EAWA,MAAA,CAAA;EAOA,IAAA,CACL,OAAA,EAAS,eAAA,EACT,YAAA,UACC,OAAA,CAAQ,cAAA;EACJ,IAAA,CACL,OAAA,EAAS,eAAA,EACT,YAAA,WACC,OAAA;EAyBU,MAAA,CAAO,aAAA,EAAe,cAAA,GAAc,OAAA,CAAA,kBAAA;EAOpC,OAAA,CAAQ,aAAA,EAAe,cAAA,GAAc,OAAA;EAKrC,IAAA,CAAK,MAAA,WAAc,OAAA,CAAA,mBAAA;AAAA;;;cCpN5B,kBAAA,SAA2B,WAAA;cACZ,SAAA,EAAW,SAAA,EAAW,aAAA,EAAe,cAAA;EAY3C,MAAA,CAAA,GAAM,OAAA;AAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index--UjWgLK-.d.mts","names":[],"sources":["../src/sip-message/outbound/index.ts"],"mappings":";;;cAEM,eAAA,SAAwB,UAAA;cACT,OAAA,WAAc,OAAA,OAAc,IAAA;AAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-BhN2W8AV.d.mts","names":[],"sources":["../src/sip-message/inbound/index.ts"],"mappings":";;;cAGM,cAAA,SAAuB,UAAA;EAAA,OACb,UAAA,CAAW,GAAA,WAAW,UAAA;AAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-Cf2Cev52.d.cts","names":[],"sources":["../src/sip-message/inbound/index.ts"],"mappings":";;;cAGM,cAAA,SAAuB,UAAA;EAAA,OACb,UAAA,CAAW,GAAA,WAAW,UAAA;AAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-XMDop59x.d.cts","names":[],"sources":["../src/sip-message/outbound/index.ts"],"mappings":";;;cAEM,eAAA,SAAwB,UAAA;cACT,OAAA,WAAc,OAAA,OAAc,IAAA;AAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import EventEmitter from \"node:events\";\nimport tls, { type TLSSocket } from \"node:tls\";\n\nimport waitFor from \"wait-for-async\";\n\nimport InboundCallSession from \"./call-session/inbound.js\";\nimport OutboundCallSession from \"./call-session/outbound.js\";\nimport Codec from \"./codec.js\";\nimport {\n InboundMessage,\n OutboundMessage,\n RequestMessage,\n ResponseMessage,\n} from \"./sip-message/index.js\";\nimport type { SoftPhoneOptions } from \"./types.js\";\nimport {\n branch,\n generateAuthorization,\n localKey,\n randomInt,\n uuid,\n} from \"./utils.js\";\n\nclass Softphone extends EventEmitter {\n public sipInfo: SoftPhoneOptions;\n public client: TLSSocket;\n public codec: Codec;\n\n public fakeDomain = `${uuid()}.invalid`;\n public fakeEmail = `${uuid()}@${this.fakeDomain}`;\n\n private intervalHandle?: NodeJS.Timeout;\n private connected = false;\n\n public constructor(sipInfo: SoftPhoneOptions) {\n super();\n if (sipInfo.codec === undefined) {\n sipInfo.codec = \"OPUS/16000\";\n }\n this.codec = new Codec(sipInfo.codec);\n this.sipInfo = sipInfo;\n if (this.sipInfo.domain === undefined) {\n this.sipInfo.domain = \"sip.ringcentral.com\";\n }\n if (this.sipInfo.outboundProxy === undefined) {\n this.sipInfo.outboundProxy = \"sip10.ringcentral.com:5096\";\n }\n const tokens = this.sipInfo.outboundProxy!.split(\":\");\n this.client = tls.connect(\n {\n host: tokens[0],\n port: parseInt(tokens[1], 10),\n rejectUnauthorized: !this.sipInfo.ignoreTlsCertErrors,\n },\n () => {\n this.connected = true;\n },\n );\n\n let cache = \"\";\n this.client.on(\"data\", (data) => {\n cache += data.toString(\"utf-8\");\n if (!cache.endsWith(\"\\r\\n\")) {\n return; // haven't received a complete message yet\n }\n // received two empty body messages\n const tempMessages = cache\n .split(\"\\r\\nContent-Length: 0\\r\\n\\r\\n\")\n .filter((message) => message.trim() !== \"\");\n cache = \"\";\n for (let i = 0; i < tempMessages.length; i++) {\n if (!tempMessages[i].includes(\"Content-Length: \")) {\n tempMessages[i] = `${tempMessages[i]}\\r\\nContent-Length: 0`;\n }\n }\n for (const message of tempMessages) {\n this.emit(\"message\", InboundMessage.fromString(message));\n }\n });\n }\n\n private instanceId = uuid();\n private registerCallId = uuid();\n\n public async register() {\n if (!this.connected) {\n await waitFor({\n interval: 100,\n times: 100,\n condition: () => this.connected,\n });\n if (!this.connected) {\n throw new Error(\"Failed to register: connect to TLS timeout\");\n }\n }\n const sipRegister = async () => {\n const fromTag = uuid();\n const requestMessage = new RequestMessage(\n `REGISTER sip:${this.sipInfo.domain} SIP/2.0`,\n {\n Via: `SIP/2.0/TLS ${this.client.localAddress}:${this.client.localPort};rport;branch=${branch()};alias`,\n \"Max-Forwards\": \"70\",\n From: `<sip:${this.sipInfo.username}@${this.sipInfo.domain}>;tag=${fromTag}`,\n To: `<sip:${this.sipInfo.username}@${this.sipInfo.domain}>`,\n \"Call-ID\": this.registerCallId,\n Contact: `<sip:${this.sipInfo.username}@${this.client.localAddress}:${this.client.localPort};transport=TLS;ob>;reg-id=1;+sip.instance=\"<urn:uuid:${this.instanceId}>\"`,\n Expires: 3600,\n Allow:\n \"PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS\",\n },\n );\n const inboundMessage = await this.send(requestMessage, true);\n if (inboundMessage.subject.startsWith(\"SIP/2.0 200 \")) {\n // sometimes the server will return 200 OK directly\n return;\n }\n const wwwAuth = inboundMessage.getHeader(\"Www-Authenticate\")!;\n const nonce = wwwAuth.match(/, nonce=\"(.+?)\"/)![1];\n const newMessage = requestMessage.fork();\n newMessage.headers.Authorization = generateAuthorization(\n this.sipInfo,\n nonce,\n \"REGISTER\",\n );\n const message = await this.send(newMessage, true);\n if (!message.subject.startsWith(\"SIP/2.0 200 \")) {\n throw new Error(`Failed to register: ${message.subject}`);\n }\n };\n await sipRegister();\n this.intervalHandle = setInterval(\n () => {\n sipRegister().catch((error) => {\n this.emit(\"registrationError\", error);\n });\n },\n 30 * 1000, // refresh registration every 30 seconds\n );\n this.on(\"message\", (inboundMessage) => {\n if (!inboundMessage.subject.startsWith(\"INVITE sip:\")) {\n return;\n }\n const outboundMessage = new OutboundMessage(\"SIP/2.0 100 Trying\", {\n Via: inboundMessage.headers.Via,\n \"Call-ID\": inboundMessage.getHeader(\"Call-ID\"),\n From: inboundMessage.headers.From,\n To: inboundMessage.headers.To,\n CSeq: inboundMessage.headers.CSeq,\n \"Content-Length\": \"0\",\n });\n this.send(outboundMessage);\n this.emit(\"invite\", inboundMessage);\n });\n }\n\n public enableDebugMode() {\n this.on(\"message\", (message) =>\n console.log(`Receiving...(${new Date()})\\n${message.toString()}`),\n );\n const tlsWrite = this.client.write.bind(this.client);\n this.client.write = (message) => {\n console.log(`Sending...(${new Date()})\\n${message}`);\n return tlsWrite(message);\n };\n }\n\n public revoke() {\n clearInterval(this.intervalHandle);\n this.removeAllListeners();\n this.client.removeAllListeners();\n this.client.destroy();\n }\n\n public send(\n message: OutboundMessage,\n waitForReply?: true,\n ): Promise<InboundMessage>;\n public send(\n message: OutboundMessage,\n waitForReply?: false,\n ): Promise<undefined>;\n public send(message: OutboundMessage, waitForReply = false) {\n this.client.write(message.toString());\n if (!waitForReply) {\n return Promise.resolve(undefined);\n }\n return new Promise<InboundMessage>((resolve) => {\n const messageListerner = (inboundMessage: InboundMessage) => {\n // \"12563 INVITE\" vs \"12563 ACK\"\n if (\n inboundMessage.headers.CSeq.trim().split(/\\s+/)[0] !==\n message.headers.CSeq.trim().split(/\\s+/)[0]\n ) {\n return;\n }\n if (inboundMessage.subject.startsWith(\"SIP/2.0 100 \")) {\n return; // ignore\n }\n this.off(\"message\", messageListerner);\n resolve(inboundMessage);\n };\n this.on(\"message\", messageListerner);\n });\n }\n\n public async answer(inviteMessage: InboundMessage) {\n const inboundCallSession = new InboundCallSession(this, inviteMessage);\n await inboundCallSession.answer();\n return inboundCallSession;\n }\n\n // decline an inbound call\n public async decline(inviteMessage: InboundMessage) {\n const newMessage = new ResponseMessage(inviteMessage, 603);\n await this.send(newMessage);\n }\n\n public async call(callee: string) {\n const offerSDP = `\nv=0\no=- ${Date.now()} 0 IN IP4 ${this.client.localAddress}\ns=rc-softphone-ts\nc=IN IP4 ${this.client.localAddress}\nt=0 0\nm=audio ${randomInt()} RTP/SAVP ${this.codec.id} 101\na=rtpmap:${this.codec.id} ${this.codec.name}\na=rtpmap:101 telephone-event/8000\na=fmtp:101 0-15\na=sendrecv\na=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:${localKey}\n `.trim();\n const inviteMessage = new RequestMessage(\n `INVITE sip:${callee}@${this.sipInfo.domain} SIP/2.0`,\n {\n Via: `SIP/2.0/TLS ${this.client.localAddress}:${this.client.localPort};rport;branch=${branch()};alias`,\n \"Max-Forwards\": 70,\n From: `<sip:${this.sipInfo.username}@${this.sipInfo.domain}>;tag=${uuid()}`,\n To: `<sip:${callee}@${this.sipInfo.domain}>`,\n Contact: ` <sip:${this.sipInfo.username}@${this.client.localAddress}:${this.client.localPort};transport=TLS;ob>`,\n \"Call-ID\": uuid(),\n Route: `<sip:${this.sipInfo.outboundProxy};transport=tls;lr>`,\n Allow: `PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS`,\n Supported: `replaces, 100rel, timer, norefersub`,\n \"Session-Expires\": 1800,\n \"Min-SE\": 90,\n \"Content-Type\": \"application/sdp\",\n },\n offerSDP,\n );\n const inboundMessage = await this.send(inviteMessage, true);\n const proxyAuthenticate = inboundMessage.getHeader(\"Proxy-Authenticate\")!;\n const nonce = proxyAuthenticate.match(/, nonce=\"(.+?)\"/)![1];\n const newMessage = inviteMessage.fork();\n newMessage.headers[\"Proxy-Authorization\"] = generateAuthorization(\n this.sipInfo,\n nonce,\n \"INVITE\",\n );\n const progressMessage = await this.send(newMessage, true);\n const outboundCallSession = new OutboundCallSession(this, progressMessage);\n outboundCallSession.sdp = offerSDP;\n return outboundCallSession;\n }\n}\n\nexport default Softphone;\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-B_auLSJn.d.cts","names":[],"sources":["../src/sip-message/outbound/request.ts"],"mappings":";;;cAKM,cAAA,SAAuB,eAAA;cACR,OAAA,WAAc,OAAA,OAAc,IAAA;EAOxC,OAAA,CAAA;EAIA,IAAA,CAAA,GAAI,cAAA;AAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-pBe7_mYv.d.mts","names":[],"sources":["../src/sip-message/outbound/request.ts"],"mappings":";;;cAKM,cAAA,SAAuB,eAAA;cACR,OAAA,WAAc,OAAA,OAAc,IAAA;EAOxC,OAAA,CAAA;EAIA,IAAA,CAAA,GAAI,cAAA;AAAA"}
|
|
@@ -6,4 +6,5 @@ declare class ResponseMessage extends OutboundMessage {
|
|
|
6
6
|
constructor(inboundMessage: InboundMessage, responseCode: number, headers?: {}, body?: string);
|
|
7
7
|
}
|
|
8
8
|
//#endregion
|
|
9
|
-
export { ResponseMessage as t };
|
|
9
|
+
export { ResponseMessage as t };
|
|
10
|
+
//# sourceMappingURL=response-LRRpY8lX.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-LRRpY8lX.d.mts","names":[],"sources":["../src/sip-message/outbound/response.ts"],"mappings":";;;;cAIM,eAAA,SAAwB,eAAA;cAE1B,cAAA,EAAgB,cAAA,EAChB,YAAA,UACA,OAAA,OACA,IAAA;AAAA"}
|
|
@@ -6,4 +6,5 @@ declare class ResponseMessage extends OutboundMessage {
|
|
|
6
6
|
constructor(inboundMessage: InboundMessage, responseCode: number, headers?: {}, body?: string);
|
|
7
7
|
}
|
|
8
8
|
//#endregion
|
|
9
|
-
export { ResponseMessage as t };
|
|
9
|
+
export { ResponseMessage as t };
|
|
10
|
+
//# sourceMappingURL=response-ReKvb5x9.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-ReKvb5x9.d.cts","names":[],"sources":["../src/sip-message/outbound/response.ts"],"mappings":";;;;cAIM,eAAA,SAAwB,eAAA;cAE1B,cAAA,EAAgB,cAAA,EAChB,YAAA,UACA,OAAA,OACA,IAAA;AAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/sip-message/inbound/index.ts"],"sourcesContent":["import { uuid } from \"../../utils.js\";\nimport SipMessage from \"../sip-message.js\";\n\nclass InboundMessage extends SipMessage {\n public static fromString(str: string) {\n const sipMessage = new SipMessage();\n const [init, ...body] = str.split(\"\\r\\n\\r\\n\");\n sipMessage.body = body.join(\"\\r\\n\\r\\n\");\n const [subject, ...headers] = init.split(\"\\r\\n\");\n sipMessage.subject = subject;\n sipMessage.headers = Object.fromEntries(\n headers.map((line) => line.split(\": \")),\n );\n if (sipMessage.headers.To && !sipMessage.headers.To.includes(\";tag=\")) {\n sipMessage.headers.To += `;tag=${uuid()}`; // generate local tag\n }\n return sipMessage;\n }\n}\n\nexport default InboundMessage;\n"],"mappings":";;;AAGA,IAAM,iBAAN,cAA6B,WAAW;CACtC,OAAc,WAAW,KAAa;EACpC,MAAM,aAAa,IAAI,YAAY;EACnC,MAAM,CAAC,MAAM,GAAG,QAAQ,IAAI,MAAM,WAAW;AAC7C,aAAW,OAAO,KAAK,KAAK,WAAW;EACvC,MAAM,CAAC,SAAS,GAAG,WAAW,KAAK,MAAM,OAAO;AAChD,aAAW,UAAU;AACrB,aAAW,UAAU,OAAO,YAC1B,QAAQ,KAAK,SAAS,KAAK,MAAM,KAAK,CAAC,CACxC;AACD,MAAI,WAAW,QAAQ,MAAM,CAAC,WAAW,QAAQ,GAAG,SAAS,QAAQ,CACnE,YAAW,QAAQ,MAAM,QAAQ,MAAM;AAEzC,SAAO"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/sip-message/outbound/index.ts"],"sourcesContent":["import SipMessage from \"../sip-message.js\";\n\nclass OutboundMessage extends SipMessage {\n public constructor(subject = \"\", headers = {}, body = \"\") {\n super(subject, headers, body);\n this.headers[\"Content-Length\"] = this.body.length.toString();\n this.headers[\"User-Agent\"] = \"ringcentral-softphone-ts\";\n }\n}\n\nexport default OutboundMessage;\n"],"mappings":";;AAEA,IAAM,kBAAN,cAA8B,WAAW;CACvC,YAAmB,UAAU,IAAI,UAAU,EAAE,EAAE,OAAO,IAAI;AACxD,QAAM,SAAS,SAAS,KAAK;AAC7B,OAAK,QAAQ,oBAAoB,KAAK,KAAK,OAAO,UAAU;AAC5D,OAAK,QAAQ,gBAAgB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.mjs","names":[],"sources":["../../../src/sip-message/outbound/request.ts"],"sourcesContent":["import { branch } from \"../../utils.js\";\nimport OutboundMessage from \"./index.js\";\n\nlet cseq = Math.floor(Math.random() * 10000);\n\nclass RequestMessage extends OutboundMessage {\n public constructor(subject = \"\", headers = {}, body = \"\") {\n super(subject, headers, body);\n if (this.headers.CSeq === undefined) {\n this.newCseq();\n }\n }\n\n public newCseq() {\n this.headers.CSeq = `${++cseq} ${this.subject.split(\" \")[0]}`;\n }\n\n public fork() {\n const newMessage = new RequestMessage(\n this.subject,\n { ...this.headers },\n this.body,\n );\n newMessage.newCseq();\n if (newMessage.headers.Via) {\n newMessage.headers.Via = newMessage.headers.Via.replace(\n /;branch=.+?$/,\n `;branch=${branch()}`,\n );\n }\n return newMessage;\n }\n}\n\nexport default RequestMessage;\n"],"mappings":";;;AAGA,IAAI,OAAO,KAAK,MAAM,KAAK,QAAQ,GAAG,IAAM;AAE5C,IAAM,iBAAN,MAAM,uBAAuB,gBAAgB;CAC3C,YAAmB,UAAU,IAAI,UAAU,EAAE,EAAE,OAAO,IAAI;AACxD,QAAM,SAAS,SAAS,KAAK;AAC7B,MAAI,KAAK,QAAQ,SAAS,KAAA,EACxB,MAAK,SAAS;;CAIlB,UAAiB;AACf,OAAK,QAAQ,OAAO,GAAG,EAAE,KAAK,GAAG,KAAK,QAAQ,MAAM,IAAI,CAAC;;CAG3D,OAAc;EACZ,MAAM,aAAa,IAAI,eACrB,KAAK,SACL,EAAE,GAAG,KAAK,SAAS,EACnB,KAAK,KACN;AACD,aAAW,SAAS;AACpB,MAAI,WAAW,QAAQ,IACrB,YAAW,QAAQ,MAAM,WAAW,QAAQ,IAAI,QAC9C,gBACA,WAAW,QAAQ,GACpB;AAEH,SAAO"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response.mjs","names":[],"sources":["../../../src/sip-message/outbound/response.ts"],"sourcesContent":["import type InboundMessage from \"../inbound/index.js\";\nimport responseCodes from \"../response-codes.js\";\nimport OutboundMessage from \"./index.js\";\n\nclass ResponseMessage extends OutboundMessage {\n public constructor(\n inboundMessage: InboundMessage,\n responseCode: number,\n headers = {},\n body = \"\",\n ) {\n super(undefined, { ...headers }, body);\n this.subject = `SIP/2.0 ${responseCode} ${responseCodes[responseCode]}`;\n const requiredKeys = new Set([\"via\", \"from\", \"to\", \"call-id\", \"cseq\"]);\n const allKeys = Object.keys(inboundMessage.headers).reduce(\n (acc, key) => {\n acc[key.toLowerCase()] = key;\n return acc;\n },\n {} as Record<string, string>,\n );\n for (const key of requiredKeys) {\n if (allKeys[key]) {\n const originalKey = allKeys[key];\n this.headers[originalKey] = inboundMessage.headers[originalKey];\n }\n }\n }\n}\n\nexport default ResponseMessage;\n"],"mappings":";;;AAIA,IAAM,kBAAN,cAA8B,gBAAgB;CAC5C,YACE,gBACA,cACA,UAAU,EAAE,EACZ,OAAO,IACP;AACA,QAAM,KAAA,GAAW,EAAE,GAAG,SAAS,EAAE,KAAK;AACtC,OAAK,UAAU,WAAW,aAAa,GAAG,cAAc;EACxD,MAAM,eAAe,IAAI,IAAI;GAAC;GAAO;GAAQ;GAAM;GAAW;GAAO,CAAC;EACtE,MAAM,UAAU,OAAO,KAAK,eAAe,QAAQ,CAAC,QACjD,KAAK,QAAQ;AACZ,OAAI,IAAI,aAAa,IAAI;AACzB,UAAO;KAET,EAAE,CACH;AACD,OAAK,MAAM,OAAO,aAChB,KAAI,QAAQ,MAAM;GAChB,MAAM,cAAc,QAAQ;AAC5B,QAAK,QAAQ,eAAe,eAAe,QAAQ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-codes.d.cts","names":[],"sources":["../../src/sip-message/response-codes.ts"],"mappings":";cACM,aAAA;EAAA,CACH,GAAA;AAAA;AAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-codes.d.mts","names":[],"sources":["../../src/sip-message/response-codes.ts"],"mappings":";cACM,aAAA;EAAA,CACH,GAAA;AAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-codes.mjs","names":[],"sources":["../../src/sip-message/response-codes.ts"],"sourcesContent":["// Ref: https://en.wikipedia.org/wiki/List_of_SIP_response_codes'\nconst responseCodes: {\n [key: number]: string;\n} = {\n 100: \"Trying\",\n 180: \"Ringing\",\n 181: \"Call is Being Forwarded\",\n 182: \"Queued\",\n 183: \"Session Progress\",\n 199: \"Early Dialog Terminated\",\n 200: \"OK\",\n 202: \"Accepted\",\n 204: \"No Notification\",\n 300: \"Multiple Choices\",\n 301: \"Moved Permanently\",\n 302: \"Moved Temporarily\",\n 305: \"Use Proxy\",\n 380: \"Alternative Service\",\n 400: \"Bad Request\",\n 401: \"Unauthorized\",\n 402: \"Payment Required\",\n 403: \"Forbidden\",\n 404: \"Not Found\",\n 405: \"Method Not Allowed\",\n 406: \"Not Acceptable\",\n 407: \"Proxy Authentication Required\",\n 408: \"Request Timeout\",\n 409: \"Conflict\",\n 410: \"Gone\",\n 411: \"Length Required\",\n 412: \"Conditional Request Failed\",\n 413: \"Request Entity Too Large\",\n 414: \"Request-URI Too Long\",\n 415: \"Unsupported Media Type\",\n 416: \"Unsupported URI Scheme\",\n 417: \"Unknown Resource-Priority\",\n 420: \"Bad Extension\",\n 421: \"Extension Required\",\n 422: \"Session Interval Too Small\",\n 423: \"Interval Too Brief\",\n 424: \"Bad Location Information\",\n 425: \"Bad Alert Message\",\n 428: \"Use Identity Header\",\n 429: \"Provide Referrer Identity\",\n 430: \"Flow Failed\",\n 433: \"Anonymity Disallowed\",\n 436: \"Bad Identity-Info\",\n 437: \"Unsupported Certificate\",\n 438: \"Invalid Identity Header\",\n 439: \"First Hop Lacks Outbound Support\",\n 440: \"Max-Breadth Exceeded\",\n 469: \"Bad Info Package\",\n 470: \"Consent Needed\",\n 480: \"Temporarily Unavailable\",\n 481: \"Call/Transaction Does Not Exist\",\n 482: \"Loop Detected\",\n 483: \"Too Many Hops\",\n 484: \"Address Incomplete\",\n 485: \"Ambiguous\",\n 486: \"Busy Here\",\n 487: \"Request Terminated\",\n 488: \"Not Acceptable Here\",\n 489: \"Bad Event\",\n 491: \"Request Pending\",\n 493: \"Undecipherable\",\n 494: \"Security Agreement Required\",\n 500: \"Server Internal Error\",\n 501: \"Not Implemented\",\n 502: \"Bad Gateway\",\n 503: \"Service Unavailable\",\n 504: \"Server Time-out\",\n 505: \"Version Not Supported\",\n 513: \"Message Too Large\",\n 555: \"Push Notification Service Not Supported\",\n 580: \"Precondition Failure\",\n 600: \"Busy Everywhere\",\n 603: \"Decline\",\n 604: \"Does Not Exist Anywhere\",\n 606: \"Not Acceptable\",\n 607: \"Unwanted\",\n 608: \"Rejected\",\n};\n\nexport default responseCodes;\n"],"mappings":";AACA,MAAM,gBAEF;CACF,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACL,KAAK;CACN"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sip-message.mjs","names":[],"sources":["../../src/sip-message/sip-message.ts"],"sourcesContent":["class SipMessage {\n public subject: string;\n public headers: {\n [key: string]: string;\n };\n public body: string;\n\n public constructor(subject = \"\", headers = {}, body = \"\") {\n this.subject = subject;\n this.headers = headers;\n this.body = body\n .trim()\n .split(/[\\r\\n]+/)\n .join(\"\\r\\n\");\n if (this.body.length > 0) {\n this.body += \"\\r\\n\";\n }\n }\n\n public toString() {\n const r = [\n this.subject,\n ...Object.keys(this.headers).map((key) => `${key}: ${this.headers[key]}`),\n \"\",\n this.body,\n ].join(\"\\r\\n\");\n return r;\n }\n\n public getHeader(key: string): string | undefined {\n const foundKey = Object.keys(this.headers).find(\n (k) => k.toLowerCase() === key.toLowerCase(),\n );\n if (foundKey) {\n return this.headers[foundKey];\n }\n }\n}\n\nexport default SipMessage;\n"],"mappings":";AAAA,IAAM,aAAN,MAAiB;CACf;CACA;CAGA;CAEA,YAAmB,UAAU,IAAI,UAAU,EAAE,EAAE,OAAO,IAAI;AACxD,OAAK,UAAU;AACf,OAAK,UAAU;AACf,OAAK,OAAO,KACT,MAAM,CACN,MAAM,UAAU,CAChB,KAAK,OAAO;AACf,MAAI,KAAK,KAAK,SAAS,EACrB,MAAK,QAAQ;;CAIjB,WAAkB;AAOhB,SANU;GACR,KAAK;GACL,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,KAAK,QAAQ,GAAG,IAAI,IAAI,KAAK,QAAQ,OAAO;GACzE;GACA,KAAK;GACN,CAAC,KAAK,OACC;;CAGV,UAAiB,KAAiC;EAChD,MAAM,WAAW,OAAO,KAAK,KAAK,QAAQ,CAAC,MACxC,MAAM,EAAE,aAAa,KAAK,IAAI,aAAa,CAC7C;AACD,MAAI,SACF,QAAO,KAAK,QAAQ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sip-message-B2D5MPBI.d.cts","names":[],"sources":["../src/sip-message/sip-message.ts"],"mappings":";cAAM,UAAA;EACG,OAAA;EACA,OAAA;IAAA,CACJ,GAAA;EAAA;EAEI,IAAA;cAEY,OAAA,WAAc,OAAA,OAAc,IAAA;EAYxC,QAAA,CAAA;EAUA,SAAA,CAAU,GAAA;AAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sip-message-PaPho4qU.d.mts","names":[],"sources":["../src/sip-message/sip-message.ts"],"mappings":";cAAM,UAAA;EACG,OAAA;EACA,OAAA;IAAA,CACJ,GAAA;EAAA;EAEI,IAAA;cAEY,OAAA,WAAc,OAAA,OAAc,IAAA;EAYxC,QAAA,CAAA;EAUA,SAAA,CAAU,GAAA;AAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-DOQ9wmX6.d.mts","names":[],"sources":["../src/types.ts"],"mappings":";KAAY,gBAAA;EACV,MAAA;EACA,aAAA;EACA,QAAA;EACA,QAAA;EACA,eAAA;EACA,KAAA;EACA,mBAAA;AAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-DZxCsbZE.d.cts","names":[],"sources":["../src/types.ts"],"mappings":";KAAY,gBAAA;EACV,MAAA;EACA,aAAA;EACA,QAAA;EACA,QAAA;EACA,eAAA;EACA,KAAA;EACA,mBAAA;AAAA"}
|
package/dist/utils.d.cts
CHANGED
|
@@ -9,4 +9,5 @@ declare const withoutTag: (s: string) => string;
|
|
|
9
9
|
declare const extractAddress: (s: string) => string | undefined;
|
|
10
10
|
declare const localKey: string;
|
|
11
11
|
//#endregion
|
|
12
|
-
export { branch, extractAddress, generateAuthorization, localKey, randomInt, uuid, withoutTag };
|
|
12
|
+
export { branch, extractAddress, generateAuthorization, localKey, randomInt, uuid, withoutTag };
|
|
13
|
+
//# sourceMappingURL=utils.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.cts","names":[],"sources":["../src/utils.ts"],"mappings":";;;cAmBa,qBAAA,GACX,OAAA,EAAS,gBAAA,EACT,KAAA,UACA,MAAA;AAAA,cAmBW,IAAA;AAAA,cACA,MAAA;AAAA,cAEA,SAAA;AAAA,cAGA,UAAA,GAAc,CAAA;AAAA,cACd,cAAA,GAAkB,CAAA;AAAA,cAGlB,QAAA"}
|
package/dist/utils.d.mts
CHANGED
|
@@ -9,4 +9,5 @@ declare const withoutTag: (s: string) => string;
|
|
|
9
9
|
declare const extractAddress: (s: string) => string | undefined;
|
|
10
10
|
declare const localKey: string;
|
|
11
11
|
//#endregion
|
|
12
|
-
export { branch, extractAddress, generateAuthorization, localKey, randomInt, uuid, withoutTag };
|
|
12
|
+
export { branch, extractAddress, generateAuthorization, localKey, randomInt, uuid, withoutTag };
|
|
13
|
+
//# sourceMappingURL=utils.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.mts","names":[],"sources":["../src/utils.ts"],"mappings":";;;cAmBa,qBAAA,GACX,OAAA,EAAS,gBAAA,EACT,KAAA,UACA,MAAA;AAAA,cAmBW,IAAA;AAAA,cACA,MAAA;AAAA,cAEA,SAAA;AAAA,cAGA,UAAA,GAAc,CAAA;AAAA,cACd,cAAA,GAAkB,CAAA;AAAA,cAGlB,QAAA"}
|
package/dist/utils.mjs
CHANGED
|
@@ -23,3 +23,5 @@ const extractAddress = (s) => s.match(/<(sip:.+?)>/)?.[1];
|
|
|
23
23
|
const localKey = crypto.randomBytes(30).toString("base64").replace(/=+$/, "");
|
|
24
24
|
//#endregion
|
|
25
25
|
export { branch, extractAddress, generateAuthorization, localKey, randomInt, uuid, withoutTag };
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=utils.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.mjs","names":[],"sources":["../src/utils.ts"],"sourcesContent":["import crypto from \"node:crypto\";\n\nimport type { SoftPhoneOptions } from \"./types.js\";\n\nconst md5 = (s: string) => crypto.createHash(\"md5\").update(s).digest(\"hex\");\n\nconst generateResponse = (\n sipInfo: SoftPhoneOptions,\n endpoint: string,\n nonce: string,\n) => {\n const ha1 = md5(\n `${sipInfo.authorizationId}:${sipInfo.domain}:${sipInfo.password}`,\n );\n const ha2 = md5(endpoint);\n const response = md5(`${ha1}:${nonce}:${ha2}`);\n return response;\n};\n\nexport const generateAuthorization = (\n sipInfo: SoftPhoneOptions,\n nonce: string,\n method: \"REGISTER\" | \"INVITE\",\n) => {\n const authObj = {\n \"Digest algorithm\": \"MD5\",\n username: sipInfo.authorizationId,\n realm: sipInfo.domain,\n nonce,\n uri: `sip:${sipInfo.domain}`,\n response: generateResponse(\n sipInfo,\n `${method}:sip:${sipInfo.domain}`,\n nonce,\n ),\n };\n return Object.entries(authObj)\n .map(([key, value]) => `${key}=\"${value}\"`)\n .join(\", \");\n};\n\nexport const uuid = () => crypto.randomUUID();\nexport const branch = () => `z9hG4bK-${uuid()}`;\n\nexport const randomInt = () =>\n Math.floor(Math.random() * (65535 - 1024 + 1)) + 1024;\n\nexport const withoutTag = (s: string) => s.replace(/;tag=.*$/, \"\");\nexport const extractAddress = (s: string) => s.match(/<(sip:.+?)>/)?.[1];\n\nconst keyAndSalt = crypto.randomBytes(30);\nexport const localKey = keyAndSalt.toString(\"base64\").replace(/=+$/, \"\");\n"],"mappings":";;AAIA,MAAM,OAAO,MAAc,OAAO,WAAW,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,MAAM;AAE3E,MAAM,oBACJ,SACA,UACA,UACG;AAMH,QADiB,IAAI,GAJT,IACV,GAAG,QAAQ,gBAAgB,GAAG,QAAQ,OAAO,GAAG,QAAQ,WAG/B,CAAC,GAAG,MAAM,GADzB,IAAI,SAC2B,GAC5B;;AAGjB,MAAa,yBACX,SACA,OACA,WACG;CACH,MAAM,UAAU;EACd,oBAAoB;EACpB,UAAU,QAAQ;EAClB,OAAO,QAAQ;EACf;EACA,KAAK,OAAO,QAAQ;EACpB,UAAU,iBACR,SACA,GAAG,OAAO,OAAO,QAAQ,UACzB,MACD;EACF;AACD,QAAO,OAAO,QAAQ,QAAQ,CAC3B,KAAK,CAAC,KAAK,WAAW,GAAG,IAAI,IAAI,MAAM,GAAG,CAC1C,KAAK,KAAK;;AAGf,MAAa,aAAa,OAAO,YAAY;AAC7C,MAAa,eAAe,WAAW,MAAM;AAE7C,MAAa,kBACX,KAAK,MAAM,KAAK,QAAQ,GAAI,MAAkB,GAAG;AAEnD,MAAa,cAAc,MAAc,EAAE,QAAQ,YAAY,GAAG;AAClE,MAAa,kBAAkB,MAAc,EAAE,MAAM,cAAc,GAAG;AAGtE,MAAa,WADM,OAAO,YAAY,GACd,CAAW,SAAS,SAAS,CAAC,QAAQ,OAAO,GAAG"}
|