fix: reduce event expiration to 20s and fix foreground service crash

- Change EXPIRATION_SECONDS from 300 to 20 for all call signaling
  events (offer, answer, ICE, hangup, reject, renegotiate)
- Change MAX_EVENT_AGE_SECONDS from 30 to 20 to match
- Update NIP-AC doc accordingly
- Fix SecurityException crash on SDK 36: phoneCall foreground service
  type requires MANAGE_OWN_CALLS permission. Switch to microphone
  type which only needs RECORD_AUDIO (already granted).

https://claude.ai/code/session_017hZm7yu7CzmcQgZGSaqSXS
This commit is contained in:
Claude
2026-04-02 01:28:00 +00:00
parent d93b384f72
commit 1016e46d50
10 changed files with 11 additions and 11 deletions
@@ -215,7 +215,7 @@ This NIP does not mandate specific STUN or TURN servers. Clients SHOULD:
## Implementation Notes
- The `call-id` tag MUST be a UUID that is unique per call session. All signaling events for the same call share the same `call-id`.
- Events SHOULD have short expiration times (~5 minutes) since signaling data is ephemeral and has no long-term value.
- Events SHOULD have short expiration times (~20 seconds) since signaling data is ephemeral and has no long-term value.
- Clients SHOULD implement a ringing timeout (e.g., 60 seconds). If no answer is received, the call transitions to a "timed out" state.
- Clients SHOULD use a foreground service or equivalent mechanism to keep calls active when the app is backgrounded.
- The WebRTC `PeerConnection` SHOULD use Unified Plan SDP semantics.
@@ -48,7 +48,7 @@ class CallAnswerEvent(
companion object {
const val KIND = 25051
const val ALT_DESCRIPTION = "WebRTC call answer"
const val EXPIRATION_SECONDS = 300L
const val EXPIRATION_SECONDS = 20L
fun build(
sdpAnswer: String,
@@ -48,7 +48,7 @@ class CallHangupEvent(
companion object {
const val KIND = 25053
const val ALT_DESCRIPTION = "WebRTC call hangup"
const val EXPIRATION_SECONDS = 300L
const val EXPIRATION_SECONDS = 20L
fun build(
peerPubKey: HexKey,
@@ -48,7 +48,7 @@ class CallIceCandidateEvent(
companion object {
const val KIND = 25052
const val ALT_DESCRIPTION = "WebRTC ICE candidate"
const val EXPIRATION_SECONDS = 300L
const val EXPIRATION_SECONDS = 20L
fun build(
candidateJson: String,
@@ -53,7 +53,7 @@ class CallOfferEvent(
companion object {
const val KIND = 25050
const val ALT_DESCRIPTION = "WebRTC call offer"
const val EXPIRATION_SECONDS = 300L // 5 minutes
const val EXPIRATION_SECONDS = 20L
fun build(
sdpOffer: String,
@@ -48,7 +48,7 @@ class CallRejectEvent(
companion object {
const val KIND = 25054
const val ALT_DESCRIPTION = "WebRTC call rejection"
const val EXPIRATION_SECONDS = 300L
const val EXPIRATION_SECONDS = 20L
fun build(
callerPubKey: HexKey,
@@ -48,7 +48,7 @@ class CallRenegotiateEvent(
companion object {
const val KIND = 25055
const val ALT_DESCRIPTION = "WebRTC call renegotiation"
const val EXPIRATION_SECONDS = 300L
const val EXPIRATION_SECONDS = 20L
fun build(
sdpOffer: String,