From 01eb1dcd28e4c0d7fb89050431caf2dc2f2774ab Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 1 Apr 2026 19:48:01 -0400 Subject: [PATCH] Improves the language of the NIP --- .../quartz/nipACWebRtcCalls/NIP-AC.md | 70 +++++-------------- 1 file changed, 19 insertions(+), 51 deletions(-) diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/NIP-AC.md b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/NIP-AC.md index a0b8338f6..0aab7141a 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/NIP-AC.md +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/NIP-AC.md @@ -6,11 +6,9 @@ WebRTC Calls `draft` `optional` -This NIP defines a protocol for establishing peer-to-peer voice and video calls between Nostr users using WebRTC, with Nostr relays serving as the signaling transport. - -## Motivation - -Nostr users currently lack a way to make real-time voice or video calls without relying on centralized services. By using Nostr relays for WebRTC signaling and public STUN servers for NAT traversal, calls can be established in a fully decentralized manner — no custom server infrastructure is required. Once a WebRTC peer connection is established, the relay is no longer involved in the media stream. +This NIP defines a protocol for establishing private peer-to-peer voice and video calls between Nostr +users using WebRTC, with Nostr relays serving as the signaling transport and public STUN servers for +NAT traversal — no custom server infrastructure is required ## Overview @@ -23,7 +21,9 @@ The protocol works as follows: 5. Both parties exchange **ICE candidates** as gift-wrapped events for NAT traversal 6. A **direct WebRTC peer connection** is established for audio/video -All signaling events MUST be gift-wrapped using [NIP-59](https://github.com/nostr-protocol/nips/blob/master/59.md) for metadata privacy. Events are signed by the sender's key and wrapped directly (without the seal layer) — the gift wrap's random ephemeral key already hides the sender from relay operators. +All signaling events MUST be gift-wrapped using [NIP-59](https://github.com/nostr-protocol/nips/blob/master/59.md) for metadata privacy. +Events are signed by the sender's key and wrapped directly (without the seal layer) — the gift wrap's +random ephemeral key already hides the sender from relay operators. ## Event Kinds @@ -44,8 +44,6 @@ All signaling events MUST include: |---------------|-------------------------------------------------------|----------| | `p` | Hex pubkey of the recipient | YES | | `call-id` | UUID identifying the call session | YES | -| `expiration` | Unix timestamp ([NIP-40](https://github.com/nostr-protocol/nips/blob/master/40.md)), SHOULD be ~5 minutes from `created_at` | YES | -| `alt` | Human-readable description ([NIP-31](https://github.com/nostr-protocol/nips/blob/master/31.md)) | YES | Additional tags for **Call Offer** (kind 25050): @@ -59,21 +57,16 @@ Additional tags for **Call Offer** (kind 25050): The `content` field contains the SDP offer string. -```json +```yaml { "kind": 25050, - "pubkey": "", - "created_at": 1234567890, "content": "v=0\r\no=- 4611731400430051336 2 IN IP4 127.0.0.1\r\n...", "tags": [ ["p", ""], ["call-id", "550e8400-e29b-41d4-a716-446655440000"], - ["call-type", "video"], - ["expiration", "1234568190"], - ["alt", "WebRTC call offer"] + ["call-type", "video"] ], - "id": "", - "sig": "" + # other fields } ``` @@ -81,20 +74,15 @@ The `content` field contains the SDP offer string. The `content` field contains the SDP answer string. -```json +```yaml { "kind": 25051, - "pubkey": "", - "created_at": 1234567895, "content": "v=0\r\no=- 4611731400430051337 2 IN IP4 127.0.0.1\r\n...", "tags": [ ["p", ""], ["call-id", "550e8400-e29b-41d4-a716-446655440000"], - ["expiration", "1234568195"], - ["alt", "WebRTC call answer"] ], - "id": "", - "sig": "" + # other fields } ``` @@ -102,20 +90,15 @@ The `content` field contains the SDP answer string. The `content` field contains the ICE candidate as a JSON string with the fields `candidate`, `sdpMid`, and `sdpMLineIndex`. -```json +```yaml { "kind": 25052, - "pubkey": "", - "created_at": 1234567896, "content": "{\"candidate\":\"candidate:842163049 1 udp 1677729535 203.0.113.1 44323 typ srflx raddr 0.0.0.0 rport 0 generation 0\",\"sdpMid\":\"0\",\"sdpMLineIndex\":0}", "tags": [ ["p", ""], ["call-id", "550e8400-e29b-41d4-a716-446655440000"], - ["expiration", "1234568196"], - ["alt", "WebRTC ICE candidate"] ], - "id": "", - "sig": "" + # other fields } ``` @@ -123,20 +106,15 @@ The `content` field contains the ICE candidate as a JSON string with the fields The `content` field MAY contain a human-readable reason or be empty. -```json +```yaml { "kind": 25053, - "pubkey": "", - "created_at": 1234568000, "content": "", "tags": [ ["p", ""], ["call-id", "550e8400-e29b-41d4-a716-446655440000"], - ["expiration", "1234568300"], - ["alt", "WebRTC call hangup"] ], - "id": "", - "sig": "" + # other fields } ``` @@ -144,20 +122,15 @@ The `content` field MAY contain a human-readable reason or be empty. The `content` field MAY contain a reason or be empty. -```json +```yaml { "kind": 25054, - "pubkey": "", - "created_at": 1234567893, "content": "", "tags": [ ["p", ""], ["call-id", "550e8400-e29b-41d4-a716-446655440000"], - ["expiration", "1234568193"], - ["alt", "WebRTC call rejection"] ], - "id": "", - "sig": "" + # other fields } ``` @@ -165,20 +138,15 @@ The `content` field MAY contain a reason or be empty. Used for mid-call changes such as toggling video on/off. The `content` field contains a new SDP offer. -```json +```yaml { "kind": 25055, - "pubkey": "", - "created_at": 1234568100, "content": "v=0\r\no=- 4611731400430051338 3 IN IP4 127.0.0.1\r\n...", "tags": [ ["p", ""], ["call-id", "550e8400-e29b-41d4-a716-446655440000"], - ["expiration", "1234568400"], - ["alt", "WebRTC call renegotiation"] ], - "id": "", - "sig": "" + # other fields } ```