@@ -77,7 +77,6 @@ class Program
7777 private static Microsoft . Extensions . Logging . ILogger logger = NullLogger . Instance ;
7878 private static NostrClient ? nostrClient ;
7979 private static RTCPeerConnection ? peerConnection ;
80- private static string ? localPeerId ;
8180 private static string ? remotePeerId ;
8281
8382 // Nostr identity for this process.
@@ -91,7 +90,17 @@ class Program
9190 private static ECXOnlyPubKey remotePubKey =
9291 ECXOnlyPubKey . Create ( Convert . FromHexString ( remotePubKeyHex ) ) ;
9392 private static bool isOfferer = false ;
94- private static bool signallingStarted = false ; // Track if offer/answer exchange has started
93+ private static bool signallingStarted = false ; // Track if offer/answer exchange has started
94+
95+ // Pending remote ICE candidates received before the remote description
96+ // has been applied. They get drained once setRemoteDescription
97+ // succeeds. Without buffering, an IceCandidate that arrives at the
98+ // offerer before the Answer (Nostr does not preserve ordering across
99+ // events) would be applied to a peer connection with no remote
100+ // description and the ICE checks against the answerer would never
101+ // start.
102+ private static readonly List < RTCIceCandidateInit > pendingRemoteCandidates = new ( ) ;
103+ private static bool remoteDescriptionApplied = false ;
95104
96105 static async Task Main ( string [ ] args )
97106 {
@@ -112,10 +121,7 @@ static async Task Main(string[] args)
112121 //localPrivateKey = ECPrivKey.Create(localPrivKeyBytes);
113122 //localPubKeyHex = localPrivateKey.CreateXOnlyPubKey().ToHex();
114123
115- localPeerId = localPubKeyHex [ ..8 ] ;
116- Console . WriteLine ( $ "Your Peer ID (short): { localPeerId } ") ;
117124 Console . WriteLine ( $ "Your Peer ID (full): { localPubKeyHex } ") ;
118- Console . WriteLine ( $ "Private key: { localPrivateKey . ToHex ( ) } ") ;
119125
120126 // Connect to Nostr relay
121127 Console . WriteLine ( $ "Connecting to Nostr relay at { NOSTR_RELAY_URL } ...") ;
@@ -205,7 +211,7 @@ private static async Task ConnectToNostrRelay()
205211 var filter = new NostrSubscriptionFilter
206212 {
207213 Kinds = new [ ] { WEBRTC_SIGNAL_KIND } ,
208- ReferencedPublicKeys = new [ ] { localPubKeyHex ! }
214+ ReferencedPublicKeys = new [ ] { localPubKeyHex }
209215 } ;
210216
211217 // Create subscription
@@ -222,16 +228,6 @@ private static async Task ConnectToNostrRelay()
222228 }
223229 }
224230
225- // Pending remote ICE candidates received before the remote description
226- // has been applied. They get drained once setRemoteDescription
227- // succeeds. Without buffering, an IceCandidate that arrives at the
228- // offerer before the Answer (Nostr does not preserve ordering across
229- // events) would be applied to a peer connection with no remote
230- // description and the ICE checks against the answerer would never
231- // start.
232- private static readonly System . Collections . Generic . List < RTCIceCandidateInit > pendingRemoteCandidates = new ( ) ;
233- private static bool remoteDescriptionApplied = false ;
234-
235231 private static void DrainPendingRemoteCandidates ( )
236232 {
237233 if ( peerConnection == null ) { return ; }
@@ -257,15 +253,14 @@ private static void OnNostrEventsReceived(object? sender, (string subscriptionId
257253 {
258254 try
259255 {
260- logger . LogDebug ( $ "Processing Nostr event: id={ nostrEvent . Id ? [ .. 8 ] } ..., kind={ nostrEvent . Kind } ") ;
256+ logger . LogDebug ( $ "Processing Nostr event: id={ nostrEvent . Id } ..., kind={ nostrEvent . Kind } ") ;
261257
262258 if ( string . IsNullOrEmpty ( nostrEvent . Content ) )
263259 {
264260 logger . LogDebug ( "Nostr event has empty content, skipping" ) ;
265261 continue ;
266262 }
267263
268-
269264 // event.Content is the NIP-44 v2 base64 ciphertext.
270265 // Inverse of the publish path: NIP-44 decrypt -> json.
271266 string jsonContent ;
@@ -276,7 +271,7 @@ private static void OnNostrEventsReceived(object? sender, (string subscriptionId
276271 catch ( Exception decryptEx )
277272 {
278273 logger . LogWarning ( decryptEx ,
279- $ "NIP-44 decrypt failed (event may be from a different peer or use a different key); skipping event { nostrEvent . Id ? [ .. 8 ] } ...") ;
274+ $ "NIP-44 decrypt failed (event may be from a different peer or use a different key); skipping event { nostrEvent . Id } ...") ;
280275 continue ;
281276 }
282277
@@ -290,15 +285,6 @@ private static void OnNostrEventsReceived(object? sender, (string subscriptionId
290285
291286 logger . LogDebug ( $ "Parsed signal message: type={ message . Type } , from={ message . PeerId } , to={ message . TargetPeerId } ") ;
292287
293- // Check if this message is for us
294- if ( message . TargetPeerId != localPeerId )
295- {
296- logger . LogDebug ( $ "Message not for us (target={ message . TargetPeerId } , local={ localPeerId } ), skipping") ;
297- continue ;
298- }
299-
300- logger . LogInformation ( $ "Received { message . Type } from peer { message . PeerId } ") ;
301-
302288 // Process the message asynchronously with error handling
303289 _ = Task . Run ( async ( ) =>
304290 {
@@ -319,7 +305,7 @@ private static void OnNostrEventsReceived(object? sender, (string subscriptionId
319305 }
320306 catch ( Exception ex )
321307 {
322- logger . LogWarning ( $ "Failed to process Nostr event: { ex . Message } ") ;
308+ logger . LogWarning ( $ "Failed to process Nostr event { nostrEvent . Id } : { ex . Message } ") ;
323309 }
324310 }
325311 }
@@ -361,7 +347,6 @@ private static async Task ProcessSignalMessage(NostrSignalMessage message)
361347 await SendSignalMessage ( new NostrSignalMessage
362348 {
363349 Type = NostrSignalType . Answer ,
364- PeerId = localPeerId ,
365350 TargetPeerId = remotePeerId ,
366351 Sdp = answerSdp . sdp
367352 } ) ;
@@ -467,7 +452,7 @@ private static async Task SendSignalMessage(NostrSignalMessage message)
467452 new NostrEventTag
468453 {
469454 TagIdentifier = "p" ,
470- Data = new List < string > { remotePubKeyHex ! }
455+ Data = new List < string > { remotePubKeyHex }
471456 }
472457 }
473458 } ;
@@ -534,17 +519,6 @@ private static RTCPeerConnection CreatePeerConnection()
534519 var testPatternSource = new VideoTestPatternSource ( vp8Codec ) ;
535520 var audioSource = new AudioExtrasSource ( new AudioEncoder ( ) , new AudioSourceOptions { AudioSource = AudioSourcesEnum . Music } ) ;
536521
537- // Tracks are SendOnly because the C# side only ever sources
538- // media (a video test pattern + a music audio source) and has no
539- // sink to render received media into. SendRecv would generate an
540- // answer SDP whose direction is incompatible with a browser
541- // offer that sets the transceivers as recvonly:
542- //
543- // InvalidAccessError: Failed to set remote answer sdp:
544- // Incompatible send direction
545- //
546- // SendOnly answers the browser cleanly and also produces a
547- // self-consistent offer when the C# side initiates the call.
548522 MediaStreamTrack videoTrack = new MediaStreamTrack ( testPatternSource . GetVideoSourceFormats ( ) , MediaStreamStatusEnum . SendOnly ) ;
549523 pc . addTrack ( videoTrack ) ;
550524 MediaStreamTrack audioTrack = new MediaStreamTrack ( audioSource . GetAudioSourceFormats ( ) , MediaStreamStatusEnum . SendOnly ) ;
@@ -572,7 +546,6 @@ private static RTCPeerConnection CreatePeerConnection()
572546 await SendSignalMessage ( new NostrSignalMessage
573547 {
574548 Type = NostrSignalType . IceCandidate ,
575- PeerId = localPeerId ,
576549 TargetPeerId = remotePeerId ,
577550 Candidate = iceCandidate . candidate ,
578551 SdpMid = iceCandidate . sdpMid ,
@@ -611,18 +584,6 @@ await SendSignalMessage(new NostrSignalMessage
611584 }
612585 else if ( state == RTCPeerConnectionState . closed )
613586 {
614- // Detach the encoded-sample event handlers BEFORE awaiting
615- // CloseVideo/CloseAudio. The audio source in particular
616- // produces a packet every ~20 ms and there are typically
617- // a handful already in flight when the peer connection
618- // transitions to closed. Without this detach each one
619- // racing past the close boundary fires
620- // pc.SendAudio -> RTPSession.SendRtpRaw
621- // -> [WRN] SendRtpRaw was called for a audio packet
622- // on a closed RTP session.
623- // Video happens to be quieter (a frame every 33 ms at
624- // 30 fps) so the symptom is mostly visible on audio,
625- // but unsubscribe both for symmetry.
626587 testPatternSource . OnVideoSourceEncodedSample -= pc . SendVideo ;
627588 audioSource . OnAudioSourceEncodedSample -= pc . SendAudio ;
628589
0 commit comments