fix(media-server): answer as DTLS server for inbound calls
With the new DTLS transport logging I could see the real failure mode for inbound calls: meta peer: DTLS state changed state=connecting meta peer: DTLS state changed state=FAILED (~2.4s later) Not a timeout — a fatal DTLS alert. Meta was rejecting our ClientHello because it hadn't yet seen our SDP answer (the answer flows to Meta via Rails' pre_accept_call / accept_call *after* create_session returns, so for ~1 second Meta has no fingerprint to verify us against). Pion treats the alert as fatal and closes the PC, which drops every later audio packet we tried to forward to Meta → Meta times out at 20s with error 138021. Flip the roles with SetAnsweringDTLSRole(DTLSRoleServer). Meta now answers its own offer's actpass as the DTLS client, and Meta only starts ClientHello after it has our answer (so our fingerprint is already known when we receive it). We've been idle until then and have everything we need to complete the handshake in one round trip. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
a08444862b
commit
0bf6a2cee8
@@ -48,12 +48,17 @@ func NewMetaPeer(cfg *config.Config, sdpOffer string, iceServers []webrtc.ICESer
|
||||
return nil, "", fmt.Errorf("set UDP port range: %w", err)
|
||||
}
|
||||
|
||||
// Meta's side finishes setting up our DTLS credentials only *after* Rails
|
||||
// calls pre_accept_call / accept_call on the Graph API. For inbound calls
|
||||
// that happens ~1 second after we've already begun the DTLS handshake, so
|
||||
// our first ClientHello is dropped. Extend the handshake window to 30s and
|
||||
// tighten the retransmission interval so a later retry lands once Meta is
|
||||
// ready.
|
||||
// For inbound WhatsApp calls we answer Meta's offer. Meta doesn't know our
|
||||
// DTLS fingerprint until Rails delivers the answer via pre_accept_call /
|
||||
// accept_call, which happens ~1 second *after* pion is ready to handshake.
|
||||
// If we're the DTLS client (pion default when remote is actpass) we blast
|
||||
// ClientHello at Meta before Meta is listening for us; Meta responds with a
|
||||
// fatal alert and pion closes the PC. Flip the roles so *we* are the DTLS
|
||||
// server: Meta becomes the client and only starts ClientHello after it has
|
||||
// our fingerprint, so the handshake happens in the right order.
|
||||
if err := se.SetAnsweringDTLSRole(webrtc.DTLSRoleServer); err != nil {
|
||||
return nil, "", fmt.Errorf("set answering DTLS role: %w", err)
|
||||
}
|
||||
se.SetDTLSConnectContextMaker(func() (context.Context, func()) {
|
||||
return context.WithTimeout(context.Background(), 30*time.Second)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user