docs: update NIP-AC to document renegotiation answer flow and multi-device support

The code implements two protocol features not previously documented in
the NIP: (1) renegotiation responses use CallAnswer (kind 25051) to
complete the SDP handshake, and (2) self-addressed answer/reject events
notify other devices of the same user to stop ringing.

https://claude.ai/code/session_01XSjhzuVn8N4Q2hZAYMRGqM
This commit is contained in:
Claude
2026-04-02 21:42:51 +00:00
parent cea630e0fd
commit 2646d280a0
@@ -163,7 +163,7 @@ The `content` field MAY contain a reason or be empty.
### Call Renegotiate (kind 25055) ### Call Renegotiate (kind 25055)
Used for mid-call changes such as toggling video on/off. The `content` field contains a new SDP offer. Used for mid-call changes such as toggling video on/off. The `content` field contains a new SDP offer. The recipient MUST respond with a `Call Answer` (kind 25051) containing the SDP answer for the renegotiation.
```json ```json
{ {
@@ -226,6 +226,23 @@ Caller Relay Callee
ICE candidates may arrive before the WebRTC peer connection is ready (e.g., the callee is still ringing). Clients MUST buffer incoming ICE candidates and apply them after `setRemoteDescription()` succeeds. Candidates buffered while ringing MUST NOT be cleared when accepting the call. ICE candidates may arrive before the WebRTC peer connection is ready (e.g., the callee is still ringing). Clients MUST buffer incoming ICE candidates and apply them after `setRemoteDescription()` succeeds. Candidates buffered while ringing MUST NOT be cleared when accepting the call.
### Mid-Call Renegotiation
Either party may send a `CallRenegotiate` (kind 25055) during an active call to change media parameters (e.g., toggling video on/off). The recipient responds with a `CallAnswer` (kind 25051):
```
Party A Relay Party B
| | |
|-- GiftWrap(Renegotiate) ----->| |
| |-- GiftWrap(Renegotiate) ----->|
| | |
| | [Party B creates SDP answer] |
| | |
|<-- GiftWrap(CallAnswer) ------|<-- GiftWrap(CallAnswer) ------|
| | |
|========= Updated WebRTC P2P Connection ========================|
```
### Ending a Call ### Ending a Call
Either party may send a `CallHangup` (kind 25053) at any time. The recipient SHOULD close the WebRTC peer connection and release media resources upon receiving it. Either party may send a `CallHangup` (kind 25053) at any time. The recipient SHOULD close the WebRTC peer connection and release media resources upon receiving it.
@@ -265,9 +282,18 @@ This NIP does not mandate specific STUN or TURN servers. Clients SHOULD:
### WebRTC Configuration ### WebRTC Configuration
- The WebRTC `PeerConnection` SHOULD use Unified Plan SDP semantics. - The WebRTC `PeerConnection` SHOULD use Unified Plan SDP semantics.
- Clients MAY support call renegotiation (kind 25055) for toggling video on/off mid-call without tearing down the connection. - Clients MAY support call renegotiation (kind 25055) for toggling video on/off mid-call without tearing down the connection. When a `Call Renegotiate` event is received, the recipient creates a new SDP answer for the renegotiated session and sends it back as a `Call Answer` (kind 25051) with the same `call-id`. The initiator applies this answer via `setRemoteDescription()` to complete the renegotiation.
- ICE candidate JSON content MUST be properly escaped — SDP strings can contain quotes and backslashes that break naive string interpolation. - ICE candidate JSON content MUST be properly escaped — SDP strings can contain quotes and backslashes that break naive string interpolation.
### Multi-Device Support
When a user is logged in on multiple devices, all devices will receive and ring for incoming calls. To prevent all devices from continuing to ring after one device handles the call:
- When **accepting** a call, the callee SHOULD gift-wrap and publish an additional `Call Answer` (kind 25051) addressed to their **own pubkey** (the `p` tag set to self). Other devices of the same user that receive this self-addressed answer SHOULD stop ringing and transition to an "answered elsewhere" state.
- When **rejecting** a call, the callee SHOULD gift-wrap and publish an additional `Call Reject` (kind 25054) addressed to their **own pubkey**. Other devices SHOULD stop ringing.
These self-notification events use the same `call-id` as the original call and follow the same gift-wrapping rules. Clients receiving a self-addressed answer or reject MUST verify the `call-id` matches the currently ringing call before acting on it.
### Audio and Media ### Audio and Media
- Clients SHOULD switch `AudioManager` to `MODE_IN_COMMUNICATION` when a call connects and restore to `MODE_NORMAL` when the call ends. - Clients SHOULD switch `AudioManager` to `MODE_IN_COMMUNICATION` when a call connects and restore to `MODE_NORMAL` when the call ends.