﻿{"id":835936,"date":"2026-02-19T22:50:16","date_gmt":"2026-02-19T22:50:16","guid":{"rendered":"https:\/\/gridnet.org\/wpp\/?p=835936"},"modified":"2026-02-20T07:57:54","modified_gmt":"2026-02-20T07:57:54","slug":"gridnet-os-swarms-api-developers-guide","status":"publish","type":"post","link":"https:\/\/mag.gridnet.org\/index.php\/2026\/02\/19\/gridnet-os-swarms-api-developers-guide\/","title":{"rendered":"The GRIDNET OS Swarms API \u2014 A Complete Developer\u2019s Guide"},"content":{"rendered":"<p><!-- GRIDNET Magazine: The GRIDNET OS Swarms API \u2014 A Complete Developer's Guide --> <!-- From CVMContext to CSwarmConnection: Building Decentralized Real-Time Applications --> <\/p>\n<p>In the grand arc of computing history, every paradigm shift has been preceded by a quietly revolutionary abstraction. The relational database gave structure to chaos. The hyperlink wove a web from isolated documents. And now, in the era of pervasive surveillance and platform monopoly, the <strong>GRIDNET OS Swarms API<\/strong> offers something equally transformative: a complete, privacy-preserving framework for decentralized real-time communication \u2014 one that requires no central server, no corporate intermediary, and no surrender of personal data.<\/p>\n<p>This article provides a comprehensive, code-level tour of the Swarms API as implemented in GRIDNET OS, drawing extensively from the production Meeting dApp \u2014 a fully functional, decentralized video-conferencing application that rivals centralized alternatives while protecting user sovereignty at every layer of the stack.<\/p>\n<figure> <img decoding=\"async\" src=\"https:\/\/gridnet.org\/wpp\/wp-content\/uploads\/2026\/02\/gridnet-os-swarms-api-developers-guide-fig-1-1.svg\" alt=\"Figure 1\" style=\"max-width:100%;height:auto;\" \/><figcaption>Fig. 1 \u2014 The GRIDNET OS Swarms API class hierarchy: from the virtual machine context down to individual peer connections, each layer encapsulates complexity while exposing clean, event-driven interfaces to dApp developers.<\/figcaption><\/figure>\n<h2>1. CVMContext \u2014 The Operating System&#8217;s Nervous System<\/h2>\n<p>Every journey through the Swarms API begins at <code>CVMContext<\/code>, the singleton that represents the entire GRIDNET OS virtual machine context. Think of it as the kernel of a decentralized operating system \u2014 it manages cryptographic primitives, network connections, DNS resolution, the window manager, and critically, the <code>CSwarmsManager<\/code> instance that governs all peer-to-peer swarm activity.<\/p>\n<p>The Meeting dApp obtains its reference to the Swarms Manager through <code>CVMContext<\/code> at construction time. Note that <code>CVMContext.getInstance().getSwarmsManager<\/code> is equivalent to <code>CSwarmsManager.getInstance(vmContext)<\/code> \u2014 both return the same singleton:<\/p>\n<pre>\nlet ctx = CVMContext.getInstance();\nthis.mSwarmManager = CSwarmsManager.getInstance(this.mVMContext);\n<\/pre>\n<p><code>CVMContext<\/code> also provides essential event buses that dApps subscribe to for system-wide notifications:<\/p>\n<pre>\nctx.addConnectionStatusChangedListener(\n  this.connectionStatusChangedCallback.bind(this), this.getID\n);\nctx.addSessionKeyAvailableListener(\n  this.sessionKeyAvailabilityChangedCallback.bind(this), this.getID\n);\nctx.getSwarmsManager.addLocalStreamEventListener(\n  this.localStreamEventHandler.bind(this), this.getID\n);\n<\/pre>\n<p>This event-driven architecture is no accident. In a decentralized system, where peers may join or leave at any moment and network conditions fluctuate unpredictably, callback-based state management is not merely convenient \u2014 it is essential. The <code>CVMContext<\/code> pattern ensures that every dApp is a first-class citizen of the operating system, receiving timely notification of connection status changes, cryptographic key availability, and metadata updates without polling.<\/p>\n<figure> <img decoding=\"async\" src=\"https:\/\/gridnet.org\/wpp\/wp-content\/uploads\/2026\/02\/gridnet-os-swarms-api-developers-guide-fig-2-1.svg\" alt=\"Figure 2\" style=\"max-width:100%;height:auto;\" \/><figcaption>Fig. 2 \u2014 CVMContext acts as a centralized event hub within the decentralized OS, routing system-level events (connection changes, key availability, metadata updates) to all subscribed dApps through a clean observer pattern.<\/figcaption><\/figure>\n<h2>2. CSwarmsManager \u2014 Orchestrating the Mesh<\/h2>\n<p>If <code>CVMContext<\/code> is the kernel, then <code>CSwarmsManager<\/code> is the network subsystem. This singleton manages the lifecycle of all swarms, governs hardware resource allocation (cameras, microphones, screen capture), and provides the bridge between the operating system&#8217;s media layer and the peer-to-peer transport.<\/p>\n<p>The <code>CSwarmsManager<\/code> maintains a collection of active <code>CSwarm<\/code> instances and provides methods for joining, leaving, and discovering swarms:<\/p>\n<pre>\nexport class CSwarmsManager {\n  static getInstance(vmContext) {\n    if (CSwarmsManager.sInstance == null) {\n      CSwarmsManager.sInstance = new CSwarmsManager(vmContext);\n    }\n    return CSwarmsManager.sInstance;\n  }\n\n  constructor(vmContext) {\n    this.mVMContext = vmContext;\n    this.mSwarms = [];\n    this.mLocalStream = null;\n    this.mScreenStream = null;\n    this.mDefaultOutgressCapabilities = eConnCapabilities.data;\n  }\n}\n<\/pre>\n<p>One of the most sophisticated aspects of <code>CSwarmsManager<\/code> is its hardware resource optimization. In a world where privacy is paramount, the manager tracks which swarms actually require camera and microphone access, and releases hardware resources the moment they are no longer needed:<\/p>\n<pre>\noptimizeRequestedResources() {\n  let audioRequested = false;\n  let videoRequested = false;\n\n  for (let i = 0; i &lt; this.mSwarms.length; i++) {\n    if (this.mSwarms[i].getCamInUse) videoRequested = true;\n    if (this.mSwarms[i].getMicInUse) audioRequested = true;\n  }\n\n  if (audioAvailable &amp;&amp; !audioRequested) {\n    this.stopAudioOnly(this.mLocalStream);\n    \/\/ \"Releasing microphone as it is no longer needed..\"\n  }\n\n  if (videoAvailable &amp;&amp; !videoRequested) {\n    this.stopVideoOnly(this.mLocalStream);\n    \/\/ \"Releasing web-cam as it is no longer needed..\"\n  }\n}\n<\/pre>\n<p>This is not merely a performance optimization \u2014 it is a privacy guarantee. When no dApp requires the webcam, the LED indicator goes dark. The user&#8217;s physical environment remains private not because of a software toggle, but because the hardware resource itself is released back to the browser.<\/p>\n<figure> <img decoding=\"async\" src=\"https:\/\/gridnet.org\/wpp\/wp-content\/uploads\/2026\/02\/gridnet-os-swarms-api-developers-guide-fig-3-1.svg\" alt=\"Figure 3\" style=\"max-width:100%;height:auto;\" \/><figcaption>Fig. 3 \u2014 Hardware resources follow a strict lifecycle in CSwarmsManager. Cameras and microphones are released at the OS level when no swarm requires them, providing a physical privacy guarantee beyond software toggles.<\/figcaption><\/figure>\n<h2>3. CSwarm \u2014 The Decentralized Room<\/h2>\n<p>A <code>CSwarm<\/code> is the fundamental unit of decentralized collaboration. It represents a group of peers connected through a WebRTC mesh topology, with each participant maintaining direct peer-to-peer connections to every other participant. Unlike centralized conferencing solutions that route all media through a server, each <code>CSwarm<\/code> is a fully sovereign network.<\/p>\n<p>Every swarm possesses two identifiers: a <em>public ID<\/em> (used for signaling and discovery) and a <em>true ID<\/em> (the cryptographic identity used for authentication). This dual-identity design is fundamental to the privacy model described in the MDPI paper <em>&#8220;WebRTC Swarms: Decentralized, Incentivized, and Privacy-Preserving Signaling with Designated Verifier Zero-Knowledge Authentication&#8221;<\/em> (Skowro\u0144ski, 2025).<\/p>\n<pre>\nexport class CSwarm {\n  constructor(swarmManager, agentID, swarmID, trueID) {\n    this.mMyID = agentID || gTools.convertToArrayBuffer(\n      gTools.encodeBase58Check(gTools.getRandomVector(16))\n    );\n    this.mID = swarmID || gTools.convertToArrayBuffer(\n      CVMContext.getInstance().getMainSwarmID\n    );\n    this.mTrueID = trueID;\n\n    \/\/ Virtual devices for privacy-preserving muting\n    this.mVirtualAudioDevice = new CVirtualAudioDev();\n    this.mVirtualCamDevice = new CVirtualCamDev(640, 480);\n    this.mLocalDummyStream = new MediaStream([\n      this.mVirtualAudioDevice.getTrack,\n      this.mVirtualCamDevice.getTrack\n    ]);\n\n    \/\/ Connection pools\n    this.mPendingConnections = [];\n    this.mActiveConnections = [];\n\n    \/\/ Security state\n    this.mSwarmAuthReq = eSwarmAuthRequirement.open;\n    this.mPasswordImage = new ArrayBuffer();\n  }\n}\n<\/pre>\n<h3>3.1 Virtual Devices \u2014 The Privacy Layer<\/h3>\n<p>One of the most elegant design decisions in the Swarms API is the use of <em>virtual audio and video devices<\/em>. When a user mutes their microphone or disables their camera, the system does not simply stop sending data \u2014 it replaces the real media track with a synthetic one generated by <code>CVirtualCamDev<\/code> or <code>CVirtualAudioDev<\/code>. This ensures that the WebRTC connection remains stable (avoiding renegotiation) while revealing absolutely nothing about the user&#8217;s environment.<\/p>\n<pre>\nexport class CVirtualCamDev {\n  constructor(widthP = 640, heightP = 480) {\n    this.mEnabled = true;\n    this.mTrack = ({ width = widthP, height = heightP } = {}) =&gt; {\n      let canvas = Object.assign(\n        document.createElement(\"canvas\"), { width, height }\n      );\n      canvas.getContext('2d').fillRect(0, 0, width, height);\n      let stream = canvas.captureStream(25);\n      return Object.assign(stream.getVideoTracks()[0], {\n        enabled: this.mEnabled\n      });\n    };\n    this.mTrack = this.mTrack();\n  }\n}\n<\/pre>\n<p>The virtual camera generates a black canvas at 25 fps \u2014 indistinguishable from a network perspective from a real video feed, but revealing nothing. The virtual microphone uses a near-silent oscillator at 440 Hz with a gain of 0.1, maintaining the audio pipeline without leaking ambient sound.<\/p>\n<figure> <img decoding=\"async\" src=\"https:\/\/gridnet.org\/wpp\/wp-content\/uploads\/2026\/02\/gridnet-os-swarms-api-developers-guide-fig-4-1.svg\" alt=\"Figure 4\" style=\"max-width:100%;height:auto;\" \/><figcaption>Fig. 4 \u2014 Virtual devices replace real media tracks seamlessly using RTCRtpSender.replaceTrack(), avoiding costly SDP renegotiation while ensuring no real media leaks during muted state.<\/figcaption><\/figure>\n<h3>3.2 Swarm Security \u2014 Public vs. Private<\/h3>\n<p>A swarm can operate in two modes: <em>open<\/em> (public) or <em>private<\/em> (requiring zero-knowledge proof authentication). The transition between modes is governed by the <code>\/setkey<\/code> command, which the Meeting dApp exposes through its chat interface:<\/p>\n<pre>\nasync processCommand(cmd, connection = null) {\n  switch (cmdWord) {\n    case 'setkey':\n      if (params.length == 0) {\n        this.clearPSK();\n        this.authRequirement = eSwarmAuthRequirement.open;\n        return eSwarmCmdProcessingResult.success;\n      }\n\n      let pass = params[0];\n      if (this.isPasswordNew(pass)) {\n        let setKeyRes = await this.setPreSharedKey(pass);\n        if (setKeyRes) {\n          this.isDedicatedPSK = true;\n          this.authRequirement = eSwarmAuthRequirement.PSK_ZK;\n          this.requestAuthentication(true); \/\/ Force re-auth\n          return eSwarmCmdProcessingResult.success;\n        }\n      }\n      break;\n  }\n}\n<\/pre>\n<p>When a swarm becomes private, all active connections are immediately required to re-authenticate. Until a peer proves knowledge of the pre-shared key through the ZKP protocol, they receive only the dummy media tracks \u2014 black video and silent audio. The real media tracks are withheld at the <code>CSwarmConnection<\/code> level through the security checks embedded in the <code>unmute()<\/code> and <code>replaceVideoTrack()<\/code> methods.<\/p>\n<figure> <img decoding=\"async\" src=\"https:\/\/gridnet.org\/wpp\/wp-content\/uploads\/2026\/02\/gridnet-os-swarms-api-developers-guide-fig-5-1.svg\" alt=\"Figure 5\" style=\"max-width:100%;height:auto;\" \/><figcaption>Fig. 5 \u2014 Swarm security transitions: an open swarm becomes private when a pre-shared key is set. Peers must complete ZKP authentication to receive real media. Password changes force re-authentication of all peers.<\/figcaption><\/figure>\n<h2>4. CSwarmConnection \u2014 The Peer-to-Peer Channel<\/h2>\n<p>Each <code>CSwarmConnection<\/code> wraps a native <code>RTCPeerConnection<\/code> and adds the full spectrum of GRIDNET OS security, state management, and event handling. It is the workhorse of the Swarms API \u2014 managing ICE negotiation, track replacement, data channel messaging, keep-alive heartbeats, and the complete zero-knowledge proof authentication state machine.<\/p>\n<pre>\nexport class CSwarmConnection {\n  constructor(swarm, rtcPeerConnection, peerID, capabilities) {\n    this.mRTCConnection = rtcPeerConnection;\n    this.mSwarm = swarm;\n    this.mPeerID = peerID;\n    this.mAuthenticated = false;\n    this.mAllowedCapabilities = capabilities;\n\n    \/\/ ZKP state machine\n    this.mZKPTimer1ExpMS = 10000;  \/\/ Phase 1 timer\n    this.mZKPTimer2ExpMS = 3000;   \/\/ Phase 2 timer\n    this.mClockDrift = 2000;       \/\/ Allowed drift\n\n    \/\/ Event listener queues\n    this.mSwarmMessageEventListeners = [];\n    this.mPeerAuthenticationResultListeners = [];\n    this.mDataChannelStateChangeEventListeners = [];\n    \/\/ ... and many more\n  }\n}\n<\/pre>\n<h3>4.1 Connection Politeness \u2014 Deterministic Conflict Resolution<\/h3>\n<p>In a fully decentralized mesh, two peers may simultaneously attempt to establish a connection with each other, creating a &#8220;glare&#8221; condition. The Swarms API resolves this deterministically through the <code>isPolite<\/code> getter, which computes peer dominance by comparing the SHA-256 hashes of both peer identifiers:<\/p>\n<pre>\nget isPolite() {\n  let cf = CVMContext.getInstance().getCryptoFactory;\n  let myID = this.mSwarm.getMyID;\n  let peerID = this.mPeerID;\n\n  let mT = cf.getSHA2_256Vec(gTools.convertToArrayBuffer(myID));\n  let pT = cf.getSHA2_256Vec(gTools.convertToArrayBuffer(peerID));\n\n  if (gTools.arrayBufferToBigInt(pT) &gt;\n      gTools.arrayBufferToBigInt(mT)) {\n    return true;  \/\/ \"I'll be polite..\"\n  }\n  return false;    \/\/ \"I've dominated..\"\n}\n<\/pre>\n<p>This is a textbook implementation of the &#8220;perfect negotiation&#8221; pattern recommended by the W3C WebRTC specification, but with a uniquely GRIDNET twist: the dominance relationship is cryptographically determined from the peer identifiers, ensuring that the same peer always yields in any given connection pair \u2014 no additional signaling required.<\/p>\n<figure> <img decoding=\"async\" src=\"https:\/\/gridnet.org\/wpp\/wp-content\/uploads\/2026\/02\/gridnet-os-swarms-api-developers-guide-fig-6-1.svg\" alt=\"Figure 6\" style=\"max-width:100%;height:auto;\" \/><figcaption>Fig. 6 \u2014 When two peers simultaneously send SDP offers (a &#8220;glare&#8221; condition), the Swarms API resolves the conflict deterministically by comparing SHA-256 hashes of peer identifiers. The peer with the higher hash value dominates; the other yields.<\/figcaption><\/figure>\n<h3>4.2 Data Channel Lifecycle and Message Processing<\/h3>\n<p>The data channel is the backbone of non-media communication within a swarm. When the data channel opens, the connection transitions to active state, and \u2014 if the swarm is private \u2014 the ZKP authentication protocol begins immediately:<\/p>\n<pre>\nonDataChannelOpenEvent(event) {\n  this.setStatus(eSwarmConnectionState.active);\n\n  \/\/ Authentication gate\n  if (this.mSwarm.isPrivate) {\n    this.requestAuthentication(true);\n  }\n\n  this.setNativeConnectionID = event.target.id;\n  this.mSwarm.transferConnToActive(this.getID);\n  this.unmute(); \/\/ Attempt to send real media (blocked if private + unauthed)\n}\n<\/pre>\n<p>Incoming messages traverse a layered processing pipeline. Raw <code>ArrayBuffer<\/code> datagrams from the WebRTC data channel are first deserialized into <code>CNetMsg<\/code> containers, then into <code>CSwarmMsg<\/code> payloads. The connection&#8217;s <code>onSwarmMessage()<\/code> handler acts as a protocol router:<\/p>\n<pre>\nonSwarmMessage(message) {\n  switch (message.type) {\n    case eSwarmMsgType.keepAlive:\n      this.mLastKeepAliveReceivedMS = gTools.getTime(true);\n      break;\n\n    case eSwarmMsgType.zeroKnowledgeProof:\n      this.processZKP(message.dataBytes);\n      break;\n\n    case eSwarmMsgType.authenticationRequestVal:\n      let authData = CSwarmAuthData.instantiate(message.dataBytes);\n      this.processAuthRequestVal(authData);\n      break;\n\n    case eSwarmMsgType.authenticationRequestCand:\n      this.processAuthRequestCand(message.dataBytes);\n      break;\n\n    \/\/ ... media state notifications (mute\/unmute\/screen share)\n  }\n}\n<\/pre>\n<figure> <img decoding=\"async\" src=\"https:\/\/gridnet.org\/wpp\/wp-content\/uploads\/2026\/02\/gridnet-os-swarms-api-developers-guide-fig-7-1.svg\" alt=\"Figure 7\" style=\"max-width:100%;height:auto;\" \/><figcaption>Fig. 7 \u2014 Messages traverse four layers: raw bytes from the data channel are deserialized through CNetMsg (with protocol ID routing) into CSwarmMsg containers, then dispatched by the protocol router to the appropriate handler (ZKP, chat, media control).<\/figcaption><\/figure>\n<h2>5. CNetMsg and CSwarmMsg \u2014 The Data Encapsulation Stack<\/h2>\n<p>All data exchanged within a swarm is wrapped in a two-layer encapsulation scheme. <code>CNetMsg<\/code> provides the transport envelope (protocol ID, request type, payload), while <code>CSwarmMsg<\/code> provides the application envelope (message type, source\/destination IDs, data, timestamp, and optional cryptographic signature).<\/p>\n<p>Both classes use ASN.1 BER encoding for serialization \u2014 a deliberate choice that provides platform-independent binary encoding with built-in length prefixing, schema extensibility, and widespread tooling support:<\/p>\n<pre>\n\/\/ CSwarmMsg serialization\ngetPackedData(includeSig = true) {\n  let wrapperSeq = new asn1js.Sequence();\n  wrapperSeq.valueBlock.value.push(\n    new asn1js.Integer({ value: this.mVersion })\n  );\n\n  let mainDataSeq = new asn1js.Sequence();\n  mainDataSeq.valueBlock.value.push(\n    new asn1js.Integer({ value: this.mType })\n  );\n  mainDataSeq.valueBlock.value.push(\n    new asn1js.OctetString({ valueHex: this.mFromID })\n  );\n  mainDataSeq.valueBlock.value.push(\n    new asn1js.OctetString({ valueHex: this.mToID })\n  );\n  mainDataSeq.valueBlock.value.push(\n    new asn1js.OctetString({ valueHex: this.mData })\n  );\n  mainDataSeq.valueBlock.value.push(\n    new asn1js.Integer({ value: this.mTimestamp })\n  );\n\n  if (includeSig) {\n    mainDataSeq.valueBlock.value.push(\n      new asn1js.OctetString({ valueHex: this.mSig })\n    );\n  }\n\n  wrapperSeq.valueBlock.value.push(mainDataSeq);\n  return wrapperSeq.toBER(false);\n}\n<\/pre>\n<p>The signature mechanism uses Ed25519 (64-byte signatures), providing authentication and integrity for every message. The signature covers the concatenation of all message fields except the signature itself, preventing tampering at any layer:<\/p>\n<pre>\nsign(privKey) {\n  let concat = new CDataConcatenator();\n  concat.add(this.mFromID);\n  concat.add(this.mToID);\n  concat.add(this.mVersion);\n  concat.add(this.mData);\n  concat.add(this.mTimestamp);\n  concat.add(this.mType);\n\n  let sig = gCrypto.sign(privKey, concat.getData());\n  if (sig.byteLength == 64) {\n    this.mSig = sig;\n    return true;\n  }\n  return false;\n}\n<\/pre>\n<figure> <img decoding=\"async\" src=\"https:\/\/gridnet.org\/wpp\/wp-content\/uploads\/2026\/02\/gridnet-os-swarms-api-developers-guide-fig-8-1.svg\" alt=\"Figure 8\" style=\"max-width:100%;height:auto;\" \/><figcaption>Fig. 8 \u2014 The CSwarmMsg binary wire format uses ASN.1\/BER encoding with nested sequences. The Ed25519 signature covers the concatenation of all message fields, providing authentication and integrity guarantees.<\/figcaption><\/figure>\n<h2>6. The Meeting dApp \u2014 Putting It All Together<\/h2>\n<p>The Meeting dApp (<code>CMeeting<\/code>) is the flagship demonstration of the Swarms API. Extending <code>CWindow<\/code> (the GRIDNET OS window manager base class), it implements a complete video-conferencing experience: multi-party video, text chat with typing indicators, screen sharing, emoji reactions, and cryptographic access control \u2014 all without a single centralized server in the media path.<\/p>\n<pre>\nclass CMeeting extends CWindow {\n  constructor(positionX, positionY, width, height) {\n    super(positionX, positionY, width + 200, height,\n          meetingBody, \"\u22ee\u22ee\u22ee Meeting\", CMeeting.getIcon(), true);\n\n    this.setProtocolID = 257;  \/\/ Application-level protocol ID\n    this.mSwarm = null;        \/\/ Single swarm per meeting\n    this.mSwarmManager = CSwarmsManager.getInstance(this.mVMContext);\n    this.mPeers = [];\n    this.mMicMuted = true;\n    this.mCamMuted = true;\n    this.mSSMuted = true;\n    this.mMyID = CVMContext.getInstance().getUserID;\n  }\n}\n<\/pre>\n<p>The dApp subscribes to swarm-level events using the <code>appID<\/code> pattern \u2014 a mechanism that ensures clean teardown when the window is closed:<\/p>\n<pre>\n\/\/ Subscribing (with appID for cleanup)\nctx.addConnectionStatusChangedListener(\n  this.connectionStatusChangedCallback.bind(this),\n  this.getID   \/\/ appID \u2014 used for bulk unsubscription\n);\n\n\/\/ Cleanup on window close\nctx.getSwarmsManager.unregisterEventListenersByAppID(this.getID);\n<\/pre>\n<p>This appID-based subscription model is one of the most practical design patterns in the Swarms API. In a multi-window operating system where users may open and close dApps freely, memory leaks from dangling event listeners would be catastrophic. The <code>unregisterEventListenersByAppID()<\/code> method sweeps through every swarm, every connection, and every event queue, removing all listeners registered by a given application in a single call.<\/p>\n<figure> <img decoding=\"async\" src=\"https:\/\/gridnet.org\/wpp\/wp-content\/uploads\/2026\/02\/gridnet-os-swarms-api-developers-guide-fig-9-1.svg\" alt=\"Figure 9\" style=\"max-width:100%;height:auto;\" \/><figcaption>Fig. 9 \u2014 The Meeting dApp subscribes to events at multiple levels (CVMContext, CSwarm, CSwarmConnection) using a consistent appID pattern. On window close, a single call sweeps all listener queues across all swarms and connections, preventing memory leaks.<\/figcaption><\/figure>\n<h2>7. Media Management \u2014 Camera, Microphone, and Screen Sharing<\/h2>\n<p>The Meeting dApp exposes three media toggles: microphone, camera, and screen sharing. Each follows the same pattern: acquire the real media track, set it as the LIVE track on the swarm, then replace the dummy tracks on all active connections:<\/p>\n<pre>\nasync toggleCam() {\n  if (this.mCamMuted) {\n    \/\/ Acquire camera from browser\n    let stream = await this.mSwarmManager.startCamOnly();\n    let videoTrack = stream.getVideoTracks()[0];\n\n    \/\/ Set as LIVE track on swarm\n    await this.mSwarm.setLIVEVideoTrack(videoTrack, true);\n\n    \/\/ Notify peers\n    this.broadcastMediaState(eSwarmMsgType.unmutedCam);\n    this.mCamMuted = false;\n  } else {\n    \/\/ Replace with virtual device track\n    await this.mSwarm.mute(false, true, true, true, 1000);\n\n    \/\/ Notify peers\n    this.broadcastMediaState(eSwarmMsgType.mutedCam);\n    this.mCamMuted = true;\n\n    \/\/ Release hardware if no other swarm needs it\n    this.mSwarmManager.optimizeRequestedResources();\n  }\n}\n<\/pre>\n<p>The muting sequence deserves special attention. When the user disables their camera, the system: (1) replaces the live video track with the virtual device&#8217;s black canvas, (2) waits approximately 1 second for the replacement to propagate, (3) disables the dummy track&#8217;s data flow entirely, and (4) releases the physical camera hardware. This four-step sequence works around known Chromium bugs where simply setting <code>track.enabled = false<\/code> freezes the last frame rather than showing black.<\/p>\n<figure> <img decoding=\"async\" src=\"https:\/\/gridnet.org\/wpp\/wp-content\/uploads\/2026\/02\/gridnet-os-swarms-api-developers-guide-fig-1-1.svg0\" alt=\"Figure 10\" style=\"max-width:100%;height:auto;\" \/><figcaption>Fig. 10 \u2014 The four-step camera mute sequence works around browser bugs to ensure peers see clean black video rather than a frozen last frame, before releasing the physical hardware resource.<\/figcaption><\/figure>\n<h2>8. Connection Quality and Keep-Alive<\/h2>\n<p>The Swarms API implements a sophisticated connection quality monitoring system. Each <code>CSwarmConnection<\/code> periodically sends keep-alive datagrams, and the receiving peer measures the time between arrivals to classify connection quality:<\/p>\n<pre>\n\/\/ Connection quality thresholds (defined in CSwarm)\nthis.mConnQualityMaxThreshold    = 1000;  \/\/ ms - Excellent\nthis.mConnQualityHighThreshold   = 1500;  \/\/ ms - Good\nthis.mConnQualityMediumThreshold = 2000;  \/\/ ms - Fair\nthis.mConnQualityLowThreshold    = 3500;  \/\/ ms - Poor\nthis.mPeerReachableTimeoutMS     = 5000;  \/\/ ms - Unreachable\n<\/pre>\n<p>The Meeting dApp renders these quality levels as animated signal-strength icons, providing users with real-time visual feedback about the health of each peer connection \u2014 much like the signal bars on a mobile phone, but for peer-to-peer links.<\/p>\n<h2>9. Practical Patterns for dApp Developers<\/h2>\n<p>For developers building on the Swarms API, the Meeting dApp provides a comprehensive template. Here are the essential patterns:<\/p>\n<p><strong>Pattern 1: Swarm Lifecycle Management<\/strong><\/p>\n<pre>\n\/\/ Join (or create) a swarm \u2014 joinSwarm creates internally if needed\nswarmManager.joinSwarm(\n  trueSwarmID,                    \/\/ Swarm identifier\n  userID,                         \/\/ Your user\/agent ID\n  privKey,                        \/\/ Private key for signing\n  eConnCapabilities.audioVideo,   \/\/ Requested capabilities\n  this                            \/\/ App instance (receives callbacks)\n);\n\n\/\/ Retrieve the swarm reference after join\nlet swarm = swarmManager.findSwarmByID(trueSwarmID);\nswarm.addClientAppInstance(this); \/\/ Register for lifecycle events\n\n\/\/ Leave on close\nswarm.removeClientAppInstance(this);\n\/\/ If no clients remain, swarm auto-closes:\n\/\/ \"Killing Swarm \u2014 all client apps have quit.\"\n<\/pre>\n<p><strong>Pattern 2: Sending Application Messages<\/strong><\/p>\n<pre>\n\/\/ Send a chat message to all peers\nlet msg = new CSwarmMsg(\n  eSwarmMsgType.text,\n  swarm.getMyID,\n  new ArrayBuffer(),  \/\/ broadcast (empty destination)\n  gTools.convertToArrayBuffer(messageText)\n);\nmsg.sign(this.mPrivKey); \/\/ Optional: sign the message\n\nfor (let conn of swarm.getActiveConnections) {\n  conn.sendSwarmMessage(msg, this.setProtocolID);\n}\n<\/pre>\n<p><strong>Pattern 3: Handling Authentication Events<\/strong><\/p>\n<pre>\n\/\/ Subscribe for auth results\nconnection.addPeerAuthResultListener(function(event) {\n  if (event.result) {\n    \/\/ Peer authenticated \u2014 show unlocked icon\n    this.setPeerAuthStateInUI(event.peerID, 2);\n  } else {\n    \/\/ Authentication failed \u2014 show locked icon\n    this.setPeerAuthStateInUI(event.peerID, 1);\n  }\n}.bind(this), this.getID);\n<\/pre>\n<h2>10. Conclusion \u2014 Code as Constitution<\/h2>\n<p>The GRIDNET OS Swarms API represents something more than a technical achievement. It is a philosophical statement, encoded in JavaScript: that real-time communication is a fundamental human capability that should not require the permission of any intermediary. Every design decision \u2014 from virtual device track replacement to deterministic politeness negotiation to ASN.1-encoded message signatures \u2014 serves a single purpose: to make decentralized, privacy-preserving communication not merely possible, but <em>practical<\/em>.<\/p>\n<p>The Meeting dApp proves this is no theoretical exercise. With its full-featured video conferencing, text chat, screen sharing, and zero-knowledge access control, it stands as a production-grade demonstration that the era of server-dependent communication is drawing to a close. The code speaks for itself \u2014 and what it says is that privacy, sovereignty, and real-time collaboration are no longer competing values.<\/p>\n<p>They are, at last, the same thing.<\/p>\n<h2>References<\/h2>\n<p>[1] Skowro\u0144ski, R. (2025). &#8220;WebRTC Swarms: Decentralized, Incentivized, and Privacy-Preserving Signaling with Designated Verifier Zero-Knowledge Authentication.&#8221; <em>Future Internet<\/em>, 18(1), 13. <a href=\"https:\/\/doi.org\/10.3390\/fi18010013\">https:\/\/doi.org\/10.3390\/fi18010013<\/a><\/p>\n<p>[2] W3C. (2024). &#8220;WebRTC 1.0: Real-Time Communication Between Browsers.&#8221; <a href=\"https:\/\/www.w3.org\/TR\/webrtc\/\">https:\/\/www.w3.org\/TR\/webrtc\/<\/a><\/p>\n<p>[3] ITU-T. (2021). &#8220;X.690 \u2014 ASN.1 encoding rules: BER, CER and DER.&#8221; <a href=\"https:\/\/www.itu.int\/rec\/T-REC-X.690\">https:\/\/www.itu.int\/rec\/T-REC-X.690<\/a><\/p>\n<p>[4] GRIDNET OS. (2025). &#8220;GRIDNET OS WebUI Source \u2014 SwarmManager.js, swarmconnection.js, swarm.js, swarmmsg.js.&#8221; <a href=\"https:\/\/gridnet.org\">https:\/\/gridnet.org<\/a><\/p>\n<p>[5] Rescorla, E. (2018). &#8220;The Transport Layer Security (TLS) Protocol Version 1.3.&#8221; RFC 8446. <a href=\"https:\/\/datatracker.ietf.org\/doc\/html\/rfc8446\">https:\/\/datatracker.ietf.org\/doc\/html\/rfc8446<\/a><\/p>\n<p>[6] Bernstein, D.J. et al. (2012). &#8220;High-speed high-security signatures.&#8221; <em>Journal of Cryptographic Engineering<\/em>, 2(2), 77-89. <a href=\"https:\/\/doi.org\/10.1007\/s13389-012-0027-1\">https:\/\/doi.org\/10.1007\/s13389-012-0027-1<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the grand arc of computing history, every paradigm shift has been preceded by a quietly revolutionary abstraction. The relational database gave&#8230;<\/p>\n","protected":false},"author":1,"featured_media":835935,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[162,125,17],"tags":[168,197,145,160,142,232,173,231,196,171],"class_list":["post-835936","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development","category-documentation","category-tutorial","tag-api","tag-dapps","tag-decentralized","tag-developer-guide","tag-gridnet-os","tag-networking","tag-p2p","tag-real-time","tag-swarms-api","tag-webrtc"],"_links":{"self":[{"href":"https:\/\/mag.gridnet.org\/index.php\/wp-json\/wp\/v2\/posts\/835936","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mag.gridnet.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mag.gridnet.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mag.gridnet.org\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mag.gridnet.org\/index.php\/wp-json\/wp\/v2\/comments?post=835936"}],"version-history":[{"count":1,"href":"https:\/\/mag.gridnet.org\/index.php\/wp-json\/wp\/v2\/posts\/835936\/revisions"}],"predecessor-version":[{"id":835937,"href":"https:\/\/mag.gridnet.org\/index.php\/wp-json\/wp\/v2\/posts\/835936\/revisions\/835937"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/mag.gridnet.org\/index.php\/wp-json\/wp\/v2\/media\/835935"}],"wp:attachment":[{"href":"https:\/\/mag.gridnet.org\/index.php\/wp-json\/wp\/v2\/media?parent=835936"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mag.gridnet.org\/index.php\/wp-json\/wp\/v2\/categories?post=835936"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mag.gridnet.org\/index.php\/wp-json\/wp\/v2\/tags?post=835936"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}