Improves the language of the NIP
This commit is contained in:
@@ -6,11 +6,9 @@ WebRTC Calls
|
|||||||
|
|
||||||
`draft` `optional`
|
`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.
|
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
|
||||||
## Motivation
|
NAT traversal — no custom server infrastructure is required
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
@@ -23,7 +21,9 @@ The protocol works as follows:
|
|||||||
5. Both parties exchange **ICE candidates** as gift-wrapped events for NAT traversal
|
5. Both parties exchange **ICE candidates** as gift-wrapped events for NAT traversal
|
||||||
6. A **direct WebRTC peer connection** is established for audio/video
|
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
|
## Event Kinds
|
||||||
|
|
||||||
@@ -44,8 +44,6 @@ All signaling events MUST include:
|
|||||||
|---------------|-------------------------------------------------------|----------|
|
|---------------|-------------------------------------------------------|----------|
|
||||||
| `p` | Hex pubkey of the recipient | YES |
|
| `p` | Hex pubkey of the recipient | YES |
|
||||||
| `call-id` | UUID identifying the call session | 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):
|
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.
|
The `content` field contains the SDP offer string.
|
||||||
|
|
||||||
```json
|
```yaml
|
||||||
{
|
{
|
||||||
"kind": 25050,
|
"kind": 25050,
|
||||||
"pubkey": "<caller-hex-pubkey>",
|
|
||||||
"created_at": 1234567890,
|
|
||||||
"content": "v=0\r\no=- 4611731400430051336 2 IN IP4 127.0.0.1\r\n...",
|
"content": "v=0\r\no=- 4611731400430051336 2 IN IP4 127.0.0.1\r\n...",
|
||||||
"tags": [
|
"tags": [
|
||||||
["p", "<callee-hex-pubkey>"],
|
["p", "<callee-hex-pubkey>"],
|
||||||
["call-id", "550e8400-e29b-41d4-a716-446655440000"],
|
["call-id", "550e8400-e29b-41d4-a716-446655440000"],
|
||||||
["call-type", "video"],
|
["call-type", "video"]
|
||||||
["expiration", "1234568190"],
|
|
||||||
["alt", "WebRTC call offer"]
|
|
||||||
],
|
],
|
||||||
"id": "<event-id>",
|
# other fields
|
||||||
"sig": "<signature>"
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -81,20 +74,15 @@ The `content` field contains the SDP offer string.
|
|||||||
|
|
||||||
The `content` field contains the SDP answer string.
|
The `content` field contains the SDP answer string.
|
||||||
|
|
||||||
```json
|
```yaml
|
||||||
{
|
{
|
||||||
"kind": 25051,
|
"kind": 25051,
|
||||||
"pubkey": "<callee-hex-pubkey>",
|
|
||||||
"created_at": 1234567895,
|
|
||||||
"content": "v=0\r\no=- 4611731400430051337 2 IN IP4 127.0.0.1\r\n...",
|
"content": "v=0\r\no=- 4611731400430051337 2 IN IP4 127.0.0.1\r\n...",
|
||||||
"tags": [
|
"tags": [
|
||||||
["p", "<caller-hex-pubkey>"],
|
["p", "<caller-hex-pubkey>"],
|
||||||
["call-id", "550e8400-e29b-41d4-a716-446655440000"],
|
["call-id", "550e8400-e29b-41d4-a716-446655440000"],
|
||||||
["expiration", "1234568195"],
|
|
||||||
["alt", "WebRTC call answer"]
|
|
||||||
],
|
],
|
||||||
"id": "<event-id>",
|
# other fields
|
||||||
"sig": "<signature>"
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -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`.
|
The `content` field contains the ICE candidate as a JSON string with the fields `candidate`, `sdpMid`, and `sdpMLineIndex`.
|
||||||
|
|
||||||
```json
|
```yaml
|
||||||
{
|
{
|
||||||
"kind": 25052,
|
"kind": 25052,
|
||||||
"pubkey": "<sender-hex-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}",
|
"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": [
|
"tags": [
|
||||||
["p", "<peer-hex-pubkey>"],
|
["p", "<peer-hex-pubkey>"],
|
||||||
["call-id", "550e8400-e29b-41d4-a716-446655440000"],
|
["call-id", "550e8400-e29b-41d4-a716-446655440000"],
|
||||||
["expiration", "1234568196"],
|
|
||||||
["alt", "WebRTC ICE candidate"]
|
|
||||||
],
|
],
|
||||||
"id": "<event-id>",
|
# other fields
|
||||||
"sig": "<signature>"
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -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.
|
The `content` field MAY contain a human-readable reason or be empty.
|
||||||
|
|
||||||
```json
|
```yaml
|
||||||
{
|
{
|
||||||
"kind": 25053,
|
"kind": 25053,
|
||||||
"pubkey": "<sender-hex-pubkey>",
|
|
||||||
"created_at": 1234568000,
|
|
||||||
"content": "",
|
"content": "",
|
||||||
"tags": [
|
"tags": [
|
||||||
["p", "<peer-hex-pubkey>"],
|
["p", "<peer-hex-pubkey>"],
|
||||||
["call-id", "550e8400-e29b-41d4-a716-446655440000"],
|
["call-id", "550e8400-e29b-41d4-a716-446655440000"],
|
||||||
["expiration", "1234568300"],
|
|
||||||
["alt", "WebRTC call hangup"]
|
|
||||||
],
|
],
|
||||||
"id": "<event-id>",
|
# other fields
|
||||||
"sig": "<signature>"
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -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.
|
The `content` field MAY contain a reason or be empty.
|
||||||
|
|
||||||
```json
|
```yaml
|
||||||
{
|
{
|
||||||
"kind": 25054,
|
"kind": 25054,
|
||||||
"pubkey": "<callee-hex-pubkey>",
|
|
||||||
"created_at": 1234567893,
|
|
||||||
"content": "",
|
"content": "",
|
||||||
"tags": [
|
"tags": [
|
||||||
["p", "<caller-hex-pubkey>"],
|
["p", "<caller-hex-pubkey>"],
|
||||||
["call-id", "550e8400-e29b-41d4-a716-446655440000"],
|
["call-id", "550e8400-e29b-41d4-a716-446655440000"],
|
||||||
["expiration", "1234568193"],
|
|
||||||
["alt", "WebRTC call rejection"]
|
|
||||||
],
|
],
|
||||||
"id": "<event-id>",
|
# other fields
|
||||||
"sig": "<signature>"
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -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.
|
Used for mid-call changes such as toggling video on/off. The `content` field contains a new SDP offer.
|
||||||
|
|
||||||
```json
|
```yaml
|
||||||
{
|
{
|
||||||
"kind": 25055,
|
"kind": 25055,
|
||||||
"pubkey": "<sender-hex-pubkey>",
|
|
||||||
"created_at": 1234568100,
|
|
||||||
"content": "v=0\r\no=- 4611731400430051338 3 IN IP4 127.0.0.1\r\n...",
|
"content": "v=0\r\no=- 4611731400430051338 3 IN IP4 127.0.0.1\r\n...",
|
||||||
"tags": [
|
"tags": [
|
||||||
["p", "<peer-hex-pubkey>"],
|
["p", "<peer-hex-pubkey>"],
|
||||||
["call-id", "550e8400-e29b-41d4-a716-446655440000"],
|
["call-id", "550e8400-e29b-41d4-a716-446655440000"],
|
||||||
["expiration", "1234568400"],
|
|
||||||
["alt", "WebRTC call renegotiation"]
|
|
||||||
],
|
],
|
||||||
"id": "<event-id>",
|
# other fields
|
||||||
"sig": "<signature>"
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user