diff --git a/.changeset/calm-cats-listen.md b/.changeset/calm-cats-listen.md new file mode 100644 index 00000000..ed7a4f21 --- /dev/null +++ b/.changeset/calm-cats-listen.md @@ -0,0 +1,5 @@ +--- +'@zapo-js/voip': patch +--- + +Preserve the caller phone device JID from incoming call offers when initializing audio media. diff --git a/packages/voip/src/call/WaCallManager.ts b/packages/voip/src/call/WaCallManager.ts index 1870c801..36d09f99 100644 --- a/packages/voip/src/call/WaCallManager.ts +++ b/packages/voip/src/call/WaCallManager.ts @@ -190,6 +190,7 @@ export class WaCallManager extends EventEmitter { } const callCreator = nodeInfo.innerNode.attrs?.['call-creator'] || peerJid + const callerPn = nodeInfo.innerNode.attrs?.['caller_pn'] const isVideo = hasNodeChild(nodeInfo.innerNode, 'video') const callKey = await decryptCallKey( @@ -204,7 +205,7 @@ export class WaCallManager extends EventEmitter { ) const mediaType = isVideo ? CallMediaType.Video : CallMediaType.Audio - const info = CallInfo.newIncoming(callId, peerJid, callCreator, undefined, mediaType) + const info = CallInfo.newIncoming(callId, peerJid, callCreator, callerPn, mediaType) if (callKey) { info.encryptionKey = callKey @@ -228,7 +229,7 @@ export class WaCallManager extends EventEmitter { try { const creds = this.deps.authClient.getCurrentCredentials() const selfLid = creds?.meLid || creds?.meJid || '' - await session.initMedia(selfLid, peerJid) + await session.initMedia(selfLid, callerPn || peerJid) await session.sendIncomingPreaccept(peerJid) await session.sendIncomingRelayLatency() } catch (err) { @@ -463,7 +464,7 @@ export class WaCallManager extends EventEmitter { const creds = this.deps.authClient.getCurrentCredentials() const selfLid = creds?.meLid || creds?.meJid || '' - await session.initMedia(selfLid, session.info.peerJid) + await session.initMedia(selfLid, session.info.callerPn || session.info.peerJid) await session.sendIncomingPreaccept(session.info.peerJid) await session.sendIncomingRelayLatency() diff --git a/packages/voip/src/call/__tests__/call-manager.test.ts b/packages/voip/src/call/__tests__/call-manager.test.ts index cc701579..ace4a079 100644 --- a/packages/voip/src/call/__tests__/call-manager.test.ts +++ b/packages/voip/src/call/__tests__/call-manager.test.ts @@ -47,7 +47,7 @@ function createMockDeps(): { deps: WaVoipDeps; stores: WaVoipStores; sent: Binar return { deps, stores, sent } } -function buildOfferNode(callId: string, from = '2222222222:0@lid'): BinaryNode { +function buildOfferNode(callId: string, from = '2222222222:0@lid', callerPn?: string): BinaryNode { return { tag: 'call', attrs: { from, id: 'OFFERMSGID' }, @@ -56,7 +56,8 @@ function buildOfferNode(callId: string, from = '2222222222:0@lid'): BinaryNode { tag: 'offer', attrs: { 'call-id': callId, - 'call-creator': from + 'call-creator': from, + ...(callerPn ? { caller_pn: callerPn } : {}) }, content: [ { tag: 'audio', attrs: { enc: 'opus', rate: '16000' }, content: undefined } @@ -183,6 +184,20 @@ test('incoming offer with capacity creates a second session', async () => { assert.equal(manager.getCalls().length, 2) }) +test('incoming offer preserves the caller phone device jid', async () => { + const { deps, stores } = createMockDeps() + const manager = new WaCallManager({ deps, stores, maxConcurrentCalls: 1 }) + const callerPn = '5511999999999:3@s.whatsapp.net' + const callId = 'INCOMINGCALLWITHCALLERPN00001' + + await manager.handleCallOffer( + buildOfferNode(callId, '2222222222:0@lid', callerPn), + '2222222222:0@lid' + ) + + assert.equal(manager.getCall(callId)?.callerPn, callerPn) +}) + test('handleCallTerminate only ends the matching call', async () => { const { deps, stores } = createMockDeps() const manager = new WaCallManager({ deps, stores, maxConcurrentCalls: 2 })