Skip to content

feat: add WithPrimaryDeviceOnly to ring the peer's primary device only#5

Closed
joaodvilla wants to merge 1 commit into
purpshell:mainfrom
joaodvilla:feat/primary-device-only
Closed

feat: add WithPrimaryDeviceOnly to ring the peer's primary device only#5
joaodvilla wants to merge 1 commit into
purpshell:mainfrom
joaodvilla:feat/primary-device-only

Conversation

@joaodvilla

Copy link
Copy Markdown

feat: add WithPrimaryDeviceOnly to ring the peer's primary device only

Problem

Placing an outbound 1:1 call to a peer that has companion devices (e.g. a WhatsApp Business account with the phone + a linked Desktop) gives unreliable inbound audio: the call rings on every device, but the callee's audio often never reaches the caller (contactFrames: 0 — the relay delivers only STUN/consent, never the peer's RTP). Outbound (caller → callee) usually still flows, so the call looks connected but is one-way or silent. Sometimes the phone leg bridges, sometimes a companion, inconsistently.

Root cause

placeCall offers the call to all of the peer's registered devices (GetUserDevices → one OfferDeviceKey per device), so it rings everywhere. Ringing all devices is not itself wrong — a real WhatsApp client does the same. The gap is that the media layer is hardwired to the peer's primary device (device 0): in runMedia / NewMediaPipeline the E2E-SRTP receive keys and the expected SSRC derive from FormatE2ESrtpParticipantID(peerLID), where peerLID is the bare (device-0) LID. A real client re-targets media to whichever device actually answers; meowcaller does not.

So the offer targets N devices but the media is prepared for one (device 0). If device 0 answers, it lines up and audio flows both ways. If a companion answers — or the answer races between devices — that device's media never matches what the library prepared, so the callee's inbound RTP is not bridged/decoded (silent or garbled).

Confirmed empirically on a multi-device WhatsApp Business contact: ringing all devices gave inconsistent inbound audio (sometimes the phone, sometimes the Desktop, often silent); ringing only the phone was clean and consistent both ways.

Change

Add a WithPrimaryDeviceOnly() client option. When set, the outbound offer is restricted to the peer's primary device (device 0), matching a normal 1:1 call and removing the offer↔media mismatch. Off by default (preserves the ring-all behavior); falls back to all devices if the peer reports no device 0.

mc := meowcaller.NewClient(wa, meowcaller.WithPrimaryDeviceOnly())

Three files: logging.go (option + config field), client.go (thread it onto Client), engine.go (filter devices in placeCall). +33 / −3.

Scope (honest framing)

This does not claim full multi-device call support; it makes the offer consistent with the media path. There are two ways to close the mismatch:

  1. Re-target the media to the device that actually answers (relay keying, expected SSRC, and E2E-recv key from the accepting device's JID instead of the hardwired device 0). The complete fix, but larger — the E2E-recv-key work (deriving the receive key from the peer's real device) is one part; the relay-subscription/SSRC side would also need to follow the answering device.
  2. Ring only the device the media is already set up for (device 0) — this option.

(2) is a small, opt-in, non-breaking change that makes multi-device calls reliable today by removing the fork. (1) remains the more complete direction and is complementary.

Testing

  • go build ./..., go vet ./..., existing tests pass.
  • Verified end-to-end on a live call to a multi-device WhatsApp Business contact: before — rings phone + Desktop, inbound audio inconsistent/silent; with WithPrimaryDeviceOnly() — rings only the phone, clean two-way audio, consistently.

Outbound 1:1 calls offer to every registered device of the peer, but the
media layer is hardwired to the peer's primary device (device 0): the
E2E-SRTP receive keys and expected SSRC derive from the bare (device-0)
LID. When a companion device answers, its media never matches what the
library prepared, so the callee's inbound RTP is not bridged/decoded
(silent or garbled) for multi-device peers.

WithPrimaryDeviceOnly restricts the offer to device 0, matching a normal
1:1 call and removing the offer<->media mismatch. Off by default; falls
back to all devices if the peer reports no device 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants