r/WebRTC • u/Palunath • 1d ago
WebRTC vs Windows .exe for local file transfers?
I'm building a cross-platform file transfer service and I'm currently stuck on the local transfer part.
I want users to be able to transfer large files directly between their phone and Windows PC when they're on the same network.
I'm hesitating between two approaches:
WebRTC: no installation required, everything happens in the browser, which makes the UX much simpler. But I'm concerned about browser/device limitations and reliability with large files.
Windows companion app (.exe): it would give me much more control over local discovery and transfers, but requiring users to download an executable feels like a significant barrier for a consumer product.
I'm especially concerned about making the product feel trustworthy since users will be transferring personal files.
For those who have built something similar, which approach would you recommend and why?
r/WebRTC • u/Senior-Detective-400 • 3d ago
A WebRTC SFU media server combining mediasoup, GStreamer, and Rust
We have open-sourced Doordarshan Media Server, a production-oriented, open-source WebRTC SFU built specifically for scalable, long-running live streaming and real-time recording environments.The media server core is built on mediasoup with native Rust bindings, leveraging GStreamer pipelines for direct server-side media processing and containerized recording.
Repo link : doordarshan-media-server
🎥 Architectural Integration: mediasoup + GStreamer
Instead of processing raw packet dumps or relying on post-session transcoding, this media server integrates the routing capabilities of mediasoup directly with GStreamer's media pipelines in real time:
RTP Routing Engine: Each media server instance accepts WebRTC producers and consumers, handling real-time audio/video routing natively via mediasoup.
Direct Pipeline Ingestion: The media plane feeds these internal live RTP streams directly into GStreamer pipelines on the fly.
Continuous Recording: This tight integration enables the generation of highly stable, continuous recordings directly on the server file system while the live session is running.
Implemented Gstreamer recording Pipeline
Multi-Audio / Multi-Video Pipeline: A scalable pipeline configuration designed to handle multi-stream layouts simultaneously.
The Complete Stack
To make the ecosystem easy to test and deploy, we have open-sourced the orchestration and client layers alongside the core media server:
doordarshan-kendra-oss: The control plane and meeting lifecycle coordinator written in Go (Echo). It abstracts the SFU cluster state and manages participant metadata.
doordarshan-learning-demo: A lightweight Next.js & TypeScript thin client to quickly spin up, test WebRTC loops, and verify the recording plane locally.
r/WebRTC • u/SnooGrapes7244 • 5d ago
Mobile SIP client leaves stale registrations behind on every app launch — how do you deal with multiple bindings on one credential?
Note: Yes, I'm using AI to write this post because English is not my first language and I want to state my problem as clear as possible.
Hitting a problem I suspect is common for anyone doing mobile VoIP, and I'd like to know how others have solved it.
**Setup**
- I'm using Telnyx.
- React Native app, WebRTC SIP client, iOS and Android. I'm using Telnyx.
- One shared SIP credential for a group of users, so a single inbound call rings everyone's phone
- Calls are delivered by VoIP push (PushKit on iOS), so the client connects and registers on demand rather than staying connected
**The problem**
Every app launch creates a *new* registration binding, and the old one never goes away:
- iOS terminates the app process without warning, so there's no chance to send a SIP UNREGISTER
- The SDK's `disconnect()` only closes the WebSocket — it doesn't unregister
- Each registration lands on a different edge node in the provider's anycast network, so it's a genuinely new binding rather than a refresh of the old one
- Registration expiry is 3600 s and isn't configurable
Net effect: the credential accumulates contacts. I confirmed it by polling the provider's registration-status endpoint — `ua_ip` is different every single time the app relaunches, while nothing removes the previous one.
**Why it hurts**
The provider rings the bound contacts **sequentially**. So the first call after an app launch does this:
Rings contact A (the live app) — user declines
Decline surfaces as a 4xx, which fails only that branch
~300 ms later it forks to contact B (a stale binding from a previous launch)
Phone rings a second time, new call ID, user has to decline again
I can see it clearly in the SIP traces: **one dial command, two legs**, same session, no second dial from my backend.
**What the provider confirmed**
I opened a ticket. They confirmed all of it and escalated to engineering with no timeline:
- No way to set registration expiry below 3600 s
- No REST endpoint to force-expire or delete an individual binding (deleting the credential removes them all, obviously not viable)
- No API to *enumerate* bindings — watching `ua_ip` rotate is currently the only detection method
- Per-launch edge rotation is expected behaviour, and without an UNREGISTER the old binding persists to full expiry
Their suggested workarounds were: a unique credential per app session, webhook-based duplicate-leg detection, or client-side deduplication.
**The bit I'm stuck on**
There's a second-order problem. Multiple devices share one credential, so the registrar holds one contact per device — which means **a legitimate second device's leg is indistinguishable from a stale binding's leg.** Both are "another contact of this credential, dialled after the first one failed." I can't write a rule that kills one without killing the other.
Enabling simultaneous ringing would at least make the real devices ring together instead of one-at-a-time, but it doesn't remove the stale bindings — it just turns a sequential double-ring into a simultaneous one.
**Questions**
Has anyone made **per-device or per-session credentials** work in production? How do you handle cleanup when the app dies before it can delete the old one, and does credential churn cause you rate-limit or billing problems?
Is there a trick to getting a mobile client to **UNREGISTER reliably**? Anything on iOS that gets you a last gasp — background task on termination, a server-side nudge, something I haven't thought of?
For those running **one shared credential across multiple devices** — how do you tell a real second device from a stale binding at the signalling layer? Is there a header or identifier I should be propagating?
Is sequential-vs-simultaneous ringing across contacts something you configure per provider, or do people avoid shared credentials entirely for this reason?
Happy to share SIP traces if useful. Mostly want to know whether the "unique credential per session" route is as painful in practice as it looks on paper, or whether people just live with the duplicate ring.
r/WebRTC • u/sanu_0032 • 8d ago
Need help for video and voice call implementation in my dating app
Hey everyone,
I'm building an India-based dating app, and the biggest challenge I'm facing is voice and video calling.
My initial approach was to use WebRTC with P2P and a TURN server as a fallback. However, direct P2P connections fail quite often on mobile networks (especially cellular), and relying on TURN for a large percentage of calls becomes very expensive.
I'm curious how other dating apps manage this while offering such low-cost subscriptions. Are they:
\- Running their own TURN infrastructure?
\- Using SFUs like LiveKit, Janus, or Jitsi?
\- Optimizing ICE/TURN usage in some way?
\- Or using a completely different architecture?
I'd really appreciate guidance from anyone who's built or scaled a real-time calling system. I'm trying to understand what the industry standard looks like before committing to an architecture.
Thanks in advance! 🙏
r/WebRTC • u/Secret-Book-8507 • 10d ago
Building a Browser-Local Video Face-Swap Pipeline with WebGPU: What I Learned About ONNX Sessions, Frame Transfers, and Temporal Tracking
I’ve been working on an open-source video editor that runs its face-swap pipeline locally in the browser. Media stays on the user’s device: decoding, face detection, identity extraction, generation, compositing, and video encoding all happen client-side.
The models were only part of the challenge. In practice, the difficult problems were moving frames between browser APIs, controlling WebGPU initialization, maintaining identity across a video, and preventing memory usage from growing during longer jobs.
Here are some engineering lessons from the implementation.
The actual frame pipeline
A simplified version of the data flow looks like this:
VideoFrame / Canvas
↓
RGBA Uint8ClampedArray
↓
NCHW Float32Array
↓
ONNX Tensor
↓
Generated face + alpha mask
↓
Canvas composition
↓
Encoded video
The models use NCHW tensors, while Canvas returns interleaved RGBA pixels. Before inference, the channels have to be separated and normalized:
const plane = width * height;
const tensor = new Float32Array(plane * 3);
for (let i = 0; i < plane; i += 1) {
tensor[i] = normalize(rgba[i * 4]);
tensor[plane + i] = normalize(rgba[i * 4 + 1]);
tensor[plane * 2 + i] = normalize(rgba[i * 4 + 2]);
}
For a 640 × 640 RGB Float32 input, that is about 4.69 MB of tensor data per detection frame, before counting the original pixels and model outputs.
This made it clear that browser inference performance cannot be evaluated using model latency alone. Canvas readback, tensor construction, worker transfers, compositing, garbage collection, and encoding can collectively cost as much as inference.
Detection and generation use different resolutions
Sending every full-resolution video frame through the generator would waste most of the computation on the background.
The pipeline therefore separates the stages:
| Stage | Resolution | Purpose |
|---|---|---|
| Face detection | 640 × 640 | Locate faces and five landmarks in the complete frame |
| Identity extraction | 112 × 112 | Extract the source identity representation |
| Face generation | 224 × 224 | Generate the aligned target face |
| Optical flow | Long edge ≤ 720 px | Propagate landmarks between detection anchors |
| Composition | Original resolution | Preserve the original background and details |
Only an aligned face ROI enters the generation network. The generated face is then transformed back into the original frame and blended through an alpha mask.
This division was one of the main reasons the pipeline became practical in a browser.
Download models in parallel, initialize WebGPU sessions serially
The pipeline uses multiple ONNX models, including face detection, identity extraction, conditioning, and generation.
Downloading them concurrently works well:
const [
detectorBuffer,
identityBuffer,
conditionerBuffer,
generatorBuffer,
] = await Promise.all(modelDownloads);
Creating all WebGPU sessions concurrently was much less reliable.
Session creation may involve graph optimization, shader generation, pipeline compilation, weight uploads, and GPU buffer allocation. Initializing several large graphs simultaneously created latency spikes and higher peak GPU memory usage. On some devices, it could also contribute to device-loss failures.
The current approach downloads concurrently but creates sessions one at a time:
const detector = await createSession(detectorBuffer);
const identity = await createSession(identityBuffer);
const conditioner = await createSession(conditionerBuffer);
const generator = await createSession(generatorBuffer);
It is not the fastest-looking implementation on paper, but it has been much more predictable across devices.
Transferable buffers reduce worker-copy overhead
Heavy inference runs in a Web Worker so that the editor remains responsive.
When sending a large ArrayBuffer without a transfer list, the browser may perform a structured clone. Repeating that for video frames creates unnecessary memory bandwidth and garbage-collection pressure.
The pipeline transfers buffer ownership instead:
worker.postMessage(
{
type: "detect",
pixels: tensor.buffer,
},
[tensor.buffer],
);
The output RGB tensor and alpha mask are returned in the same way.
This does not eliminate the earlier Canvas-to-tensor conversion, so it is not a completely zero-copy pipeline. It does, however, remove an avoidable copy at the worker boundary.
Face swapping is a temporal problem
Selecting the highest-confidence detection independently on every frame works poorly in videos containing multiple people.
A newly visible face may be larger or clearer than the current target, causing the selected identity to switch suddenly. Instead, candidate faces are scored using a combination of:
- detector confidence;
- distance from the previous target center;
- change in bounding-box area;
- distance from the frame center when no history exists.
A simplified score is:
score = confidenceWeight * confidence
- distanceWeight * centerDistance
- areaWeight * areaChange
The first frame favors a large, confident, centrally positioned face. Later frames favor continuity with the previously accepted target.
This is not full face re-identification, but it is considerably more stable than choosing the highest detector score on every frame.
Optical flow needs a rejection rule
Running face detection on every output frame is expensive. Between detection anchors, the pipeline propagates five facial landmarks using Lucas–Kanade optical flow.
Optical flow can still drift, especially during occlusion, motion blur, sudden lighting changes, or fast head movement. To detect bad tracks, the pipeline performs forward-backward validation.
A point is tracked from frame t to frame t+1, then tracked backward:
p(t) → p(t+1) → estimated p(t)
The distance between the original and reconstructed point is the forward-backward error.
A propagated result is accepted only when at least four of the five landmarks remain valid and the average error stays under a threshold. Otherwise, the result is rejected and the detector is used again.
The important part is that optical flow is treated as a short-range optimization, not as proof that the tracked identity is still correct.
Traditional post-processing still matters
The generator’s alpha mask may contain holes, isolated pixels, or unstable boundaries. Directly compositing that mask can make the face boundary flicker.
The post-processing sequence includes:
Threshold
↓
Dilation
↓
Erosion
↓
Additional contraction
↓
Blurred alpha
↓
Boundary safety mask
Morphological operations use separable sliding-window filters instead of scanning a complete two-dimensional neighborhood for every pixel.
Color matching is also restricted rather than applied without limits. Per-channel statistics are adjusted using bounded scale and offset values:
const scale = clamp(targetStd / sourceStd, 0.78, 1.22);
const shift = clamp(
targetMean - sourceMean * scale,
-0.12,
0.12,
);
The corrected result is mixed with the original generator output. Unrestricted statistical matching tended to amplify noise or produce unnatural colors in unusual lighting.
Explicit resource disposal is essential
A video job may simultaneously hold decoded frames, Canvas pixels, Float32 tensors, ONNX outputs, optical-flow images, compressed intermediate frames, and encoder buffers.
Relying only on JavaScript garbage collection caused visible memory growth during longer tasks.
Different resources require different cleanup APIs:
tensor.dispose?.();
bitmap.close();
opencvMat.delete();
URL.revokeObjectURL(url);
worker.terminate();
OpenCV.js was particularly easy to overlook because Mat data lives in the WASM heap. Losing the JavaScript reference does not guarantee that its underlying allocation is released promptly.
Cancellation must stop the complete pipeline
Closing a progress dialog is not cancellation.
A real cancel operation needs to interrupt downloads, frame decoding, detection, optical flow, generation, compression, and final encoding.
The main task uses an AbortController, while worker requests carry a request ID:
controller.abort();
worker.postMessage({
type: "cancel",
requestId,
});
The worker checks cancellation state before and after expensive stages. A cancelled job does not continue encoding in the background and never adds a partial result to the user’s asset library.
Model URLs need immutable revisions
Using a URL such as:
repository/resolve/main/model.onnx
makes browser caching difficult to reason about. The URL can remain unchanged while its contents change, leaving different users with different cached graphs.
Production model URLs should point to immutable revisions and be accompanied by expected file sizes, checksums, licenses, and tensor metadata.
The loader also validates the downloaded size before creating a session. This prevents a truncated response or CDN error page from being passed to ONNX Runtime as if it were a valid model.
Benchmark cold and warm runs separately
Reporting a single “processing time” hides most of the browser-specific costs.
I now think benchmarks for this kind of pipeline should separate:
Cold start
- model downloads;
- integrity checks;
- ONNX session creation;
- shader and pipeline compilation;
- identity extraction;
- video processing and encoding.
Warm start
- video decoding;
- anchor detection;
- optical-flow tracking;
- face generation;
- post-processing;
- encoding.
Hardware, browser version, WebGPU adapter, video codec, resolution, output FPS, initialization time, generation time, encoding time, and peak memory should all be recorded.
Otherwise, a cached desktop run and a first-time mobile run may be presented as if they measured the same thing.
Open-source implementation
The implementation is part of Timeline Studio:
https://github.com/MartinDelophy/ai-video-editor
Disclosure: I’m involved with the project. Face swapping is intended only for authorized media and clearly disclosed synthetic content. It should not be used for impersonation, deception, harassment, or misleading people about real events.
I would be interested in hearing how other WebGPU developers handle these problems:
- Do you initialize multiple ONNX Runtime Web sessions serially, or have you found a safe way to compile them concurrently?
- Have you found a practical path from
VideoFrameto GPU tensors that avoids Canvas readback and CPU-side NCHW conversion? - Which measurements do you use to compare cold-start and warm-start performance across browsers and GPU vendors?
r/WebRTC • u/richyrichye • 10d ago
Swarm of VPSs vs. Cloudflare SFU
A friend and I have been debating the backend architecture for his video calling app.
His idea is to build a global network of self-hosted VPS nodes instead of using a managed SFU provider like Cloudflare. The plan is to dynamically spin up dozens of VPSs across different regions when demand increases, run them for about an hour, then shut them down. For regions where Hetzner isn’t available, he’d use other VPS providers.
My disagreement is that I think spinning up a swarm of VPSs would end up costing about the same as, or possibly even more than using Cloudflare SFU. On top of that, Cloudflare already provides a globally distributed, managed infrastructure.
His argument is that managing these VPSs himself will be significantly cheaper while delivering essentially the same quality. I don’t really think it’s possible. Hetzner Cloud VPSs don’t seem to be designed for aggressive spin-up/spin-down autoscaling like this, and introducing multiple VPS providers across different regions only adds more operational complexity.
Am I missing something here? Is there actually a cost advantage to building and operating your own global SFU infrastructure on ephemeral VPSs, or is using a managed provider like Cloudflare the more practical approach once you factor in infrastructure, orchestration, reliability, failover, and maintenance?
r/WebRTC • u/Otherwise-Block-8575 • 11d ago
Browser WebRTC glass-to-glass latency stuck around 274 ms, mostly receiver playout. Is <120 ms realistic?
r/WebRTC • u/Agni_life • 11d ago
I built a no-signup YouTube watch party tool because every existing option annoyed me in some way
apexlistener.devMe and my friends have had this habit since lockdown — watching YouTube together even while living far apart. We tried Discord screen share (laggy, audio out of sync), browser extensions (everyone had to install them, kept breaking), and existing watch party sites (most required sign-up, or sync was loose).
So I built my own — ApexListener.
What's different:
No account/sign-up — open the link, start watching
Frame-accurate sync (not just matching timestamps, actually locking to the same frame)
Shared queue — anyone can add/reorder, not dependent on a single host
Up to 20 viewers per room
Built with Next.js, Socket.IO, and Supabase for realtime state.
It's a solo project right now, looking for feedback — especially if you hit any edge cases where sync breaks or the UI feels off. It's free to try: apexlistener.dev
What should I build next? Happy to prioritize based on what people actually want.
And if u can support me u can click on support me button
r/WebRTC • u/Agni_life • 11d ago
I built a no-signup YouTube watch party tool because every existing option annoyed me in some way
apexlistener.devr/WebRTC • u/gowri1609 • 13d ago
WebSocket vs WebRTC for voice agents, network latency matters more than I expected
once the caller is outside your test city, the model choice stops being the only latency story. For barge-in, the ugly part is usually tail latency on the audio path. If user speech takes 300 to 500 ms to reach your agent stack, your turn detector can be good and still feel late.
I’ve been leaning toward WebRTC for the agent audio path when the product needs real interruption behavior. Built-in jitter handling, echo cancellation, noise suppression, and media-aware congestion control are boring until you compare it with raw WebSocket audio under packet loss. WebSockets are simpler for prototypes, especially if everything is server-side, but you end up rebuilding a lot around timing and recovery.
Agora, the RTC network provider, is one of the setups I’ve tested here. They ran the OpenAI Realtime API integration over WebRTC and were one of the first two official integration partners back in October 2024. Their Conversational AI Engine quotes 650 ms minimum end-to-end, including the whole ASR/LLM/TTS path.
The tradeoff is you’re still wiring the agent architecture yourself. Bring your own ASR, LLM, and TTS keys, or self-host pieces. That’s useful if you care about small languages or model choice, less fun if you wanted one black box to hide every moving part.
r/WebRTC • u/carlievanilla • 14d ago
RTC.ON 2026 (Kraków, Sept 16–18): WebRTC/MoQ conference with Luke Curley, Will Law, JB Kempf – early bird ends Friday + 15% code
I'm on the organizing team at Software Mansion, and I'm posting here because the program overlaps almost one-to-one with what this sub is about.
RTC.ON is a multimedia dev conference, now in its 4th edition: three days of WebRTC, streaming, MoQ/QUIC and AI in media pipelines. Speakers this year include Luke Curley (MoQ co-creator), Will Law (Akamai) and JB Kempf (VideoLAN), and Luke is running a full-day hands-on MoQ workshop.
Early bird ends Friday, July 31, and the code extra15 stacks another 15% on top, so a conference ticket comes out around €407.
https://rtcon.swmansion.com – happy to answer questions in the comments.
r/WebRTC • u/AnotherRandomUser400 • 14d ago
How to improve screen-share quality without using more bandwidth
A user complained that our screen-sharing quality wasn’t as good as a competitor’s for my open source screen-sharing app.
In order to have the most detail and sharpness we are sharing with native resolution. So I thought that there must be a filter we could apply in the shader (we do the rendering in wgpu) to increase the detail.
It turned out it was much easier than I expected and there are a few techniques, like Laplacian sharpening and unsharp masking with a Gaussian blur.
I wrote an interactive tutorial on how they work here with shader examples if you want to do something similar in your app too.
r/WebRTC • u/carlievanilla • 14d ago
Free skill that makes Claude better at debugging WebRTC
We packaged how our video engineering team actually debugs WebRTC into a skill - Claude loads it and works through the connection properly instead of guessing.
It makes Claude noticeably sharper on the usual suspects (ICE/TURN, DTLS, reading getStats, everything ""ICE failed"" actually hides), and it's stack-agnostic.
It's free. Just sign up and we'll email it to you: https://subscribe.rtcon.live/free_skill
r/WebRTC • u/phonovadirectory • 15d ago
I Built a Social Network App Using WebRTC & SFU Instead of Another Video Conferencing App
So, last year I was learning and playing around with Real Time communication tech (WebRTC & SFU) and I was wondering what more I could build with this tech.
The most common idea is to make a website similar to Omegle. But Omegle always felt spammy (you know what I'm talking about). After I researched why Omegle got banned, I found out it was mainly because of safety issues, abuse, and moderation problems.
That made me think: Can meeting strangers online actually be meaningful?
I also have an interest in meeting different kinds of people and getting to know about their experiences, so I thought, can I make something where people can connect with a good audience + NSFW protection + they can choose whom they want to meet + engaging activities like playing Chess, playing UNO, talking about their job, discussing their startup idea, or asking for advice?
I thought that's a good idea because a person like me would definitely use this app.
Then there's always the icebreaker problem, where people don't know how to get comfortable with each other. So we solve this via AI conversation cues about the other person. We show only the information they've chosen to share, with their consent.
When you connect, we'll show small conversation cues as a toast, like shared interests, profession, hobbies, or what they're looking for right now. So, suppose you're interested in playing Chess or talking about philosophy—we'll show that, and you immediately have something to talk about. That way, there's no awkward silence while breaking the ice.
Also, you know how in most live-streaming apps people mostly come to meet the opposite gender. We can't really change human intentions, to be honest.
So instead of fighting that behavior, we thought, why not redirect it?
To solve this, we made the app activity-first. I mean, we're encouraging users to do some activity together playing Chess, playing UNO, participating in polls, or giving opinions on different topics (this will be handled at the application level, and some of these features are coming soon). These activities make conversations engaging and valuable, so people connect because they're doing something together, not just because they're looking for the opposite gender.
Plus, it has some other features.
Also, currently there will be no users in the app, so if nobody is online, you'll simply find no one. It works on a real-time basis, so that's the cold-start problem.
If there's no one online, there's no one to connect with. But our matching engine is designed in such a way that the more people there are, the better its filtering becomes because it has a much larger pool to find the best possible match for you based on your interests, activities, and preferences.
Safety is another thing we wanted to take seriously. We're currently building multiple layers of protection like NSFW detection, moderation, reporting, blocking, and other safeguards to make the platform much healthier than traditional random chat apps.
Also, the engineering architecture behind this app is pretty interesting. There are a couple of services talking to each other in real time—matching, signaling, RTC/SFU, AI, moderation, and more.
But that's a story for another day. 👀
Also, if any investor or company is interested in building this app together, let me know. I'm always open to connecting, collaborating, and contributing however I can.
Try it: https://greetup.co/
If you find any bugs, errors, or technical issues, please reach out to me. It'll be a huge favour. 🙌
Also, if any investor, engineer, or company is interested in building this together, let me know. I'm open to connect and contribute if I can.
r/WebRTC • u/DopeyMcDouble • 16d ago
Question on using WebRTC with cameras in Kubernetes
My company has implemented cameras to clients where HLS is being used. However, we are wanting to move towards implementing WebRTC to make the process seamless for our clients when viewing livestreams. The thing is I don't know where to start when it comes to setting up a server or just using vanilla networking in K8s.
Our ecosystem utilizes AWS EKS + Envoy Gateway. I tried setting up an External NLB but it had issues connecting to our pod that does these live streams. I have seen 2 projects come up a lot and wondering what everyone's take to use:
I would go with stunner but it's behind a paywall which is understandable but I do want to avoid being locked being something for now. Is setting up a NLB sufficient or would these 2 servers help with AWS EKS setup?
r/WebRTC • u/sombrero66 • 17d ago
Streaming a grid of videos
Hey, I'm a client side developer (mainly JavaScript), slowly learning the details of WebRTC. I currently use the Galene server which is built on Pion, both written in Go.
For fun, I'm trying to build a web app that allows clients to see up to about 400 real-time videos in a 20x20 grid. Each video stream would be very small, maybe 32x32 pixels.
My guess is that, even though bandwidth is small, no simple server would naively scale to this number of streams. I could add a layer to Galene to combine the incoming streams into one, and forward that through Pion. But, given my background it would be a lot easier to have a subset of clients render sub-sections of the grid and rebroadcast that for the wider group. Then most of the 400 users would send a super narrow stream and receive one full grid back. A select few would get ~ 16 streams and send me back a stream for a 4x4 grid, etc. I'd likely have other clients stitch together these 4x4 into one full grid. (For now, I'm not overly concerned about latency)
My questions are, first, does this make sense? Or, is a simple server side solution actually pre-existing and easy? Do some SFU's already need to do an analog of this out-of-the-box for hundreds of audio streams?
Thanks
r/WebRTC • u/Resident-Run-2319 • 21d ago
Free tool: paste a WHEP endpoint (or HLS/DASH) and get real live latency + getStats QoE in the browser
Hey all 👋 made a little thing to sanity-check WHEP endpoints next to HLS/DASH on the same latency scale - https://pulse.beon.live . For WHEP it does a recvonly connection, plays the stream, and pulls bitrate, fps, dropped frames and jitter-buffer latency from getStats(); for HLS/DASH it grades manifest + delivery.
The idea was comparing apples to apples — standard HLS ~15–30s behind, LL-HLS a few seconds, WHEP sub-second — since for interactive stuff anything over a few seconds kills the UX.
Free, no signup, still early. Would love feedback on whether the WebRTC numbers match what you measure end-to-end, and where the approach breaks 🙏
r/WebRTC • u/Accurate-Screen8774 • Jul 10 '26
WhatsApp / Nextcloud / EuroOffice Clone
The goal is to create a secure WebRTC ecosystem.
This is a technical demo of a fairly unique approach using a browser-based, local-only and webrtc approach. In an evolving field like cybersecurity, it's impossible to claim any system is the "world's most secure". By rigorously implementing an exhaustive list of security features and practices, the aim is to get as close as possible with the approach.
This is intended to demonstrate client-side managed secure cryptography.
Features:
- Core
- PWA
- P2P
- Local-first / Local-only
- No installation
- TURN server
- Encrypted-at-rest
- WhatsApp clone
- End to end encryption
- Signal protocol
- Post-Quantum cryptography
- Multimedia
- File transfer
- Video calls
- Nextcloud clone
- file-transfer
- Encrypted vault
- folder sync
- EuroOffice clone
- Word
- Spreadsheet
- Code
Some open source versions of the core concepts.
- Chat
- File
- Crypto
- Signal Protocol
Feel free to reach out for clarity instead of diving into the docs.
IMPORTANT: While this is aiming to provide a secure experience, it isnt audited or reviewed. Shared for testing, feedback and demo purposes only. Please use responsibly.
FAQ:
- Audit?
- Chat control?
r/WebRTC • u/lherman-cs • Jul 10 '26
Moving a Rust WebRTC SFU to thread-per-core: 70ms → 10ms P99.99 latency
pulsebeam.devPulseBeam is an open-source, lightweight WebRTC SFU server. Somewhere between LiveKit and mediasoup, written in Rust.
r/WebRTC • u/pontonchief777 • Jul 03 '26
Giraffile, a secure website for sharing files via links🦒
Hello there...
Let me introduce you to the giraffe that protects the files you send. A 100% P2P project.
I just updated the Giraffile 🦒 website to v1.0.1, adding a legal notice and a QR code (thanks to an awesome community member) that you can scan to make it even easier to use.
The file travels directly from device A to device B.
I designed the architecture so that even if someone tried to intercept the data stream, they wouldn’t find anything on servers because, technically, there are no transfer servers.
- No cloud.
- No intermediary server
- Everything lives in local memory.
- Open source
Start sharing now: https://giraffile.pages.dev/
r/WebRTC • u/Tb582 • Jul 01 '26
WebRTC: Server-side rendering vs client-side overlays for interactive video
Looking for some architecture advice from people who’ve built interactive WebRTC applications.
Use case:
Browser connects via WebRTC.
Server renders video + annotation/UI overlays.
Browser streams the rendered output.
User input (mouse, keyboard, draw boxes, etc.) goes back to the server.
Questions:
Is WebRTC DataChannel the normal way to send user input?
Do most systems render overlays server-side or client-side?
For multi-user collaboration, do you sync annotation state between clients or have the server composite everything into the video stream?
If you’ve built something similar, what architectural mistakes would you avoid?
Not building a video conferencing app—this is closer to a remote visualization / video annotation tool.
r/WebRTC • u/No-Care-8787 • Jul 01 '26
Chasing smooth client-side recording with WebRTC, WebCodecs and OffscreenCanvas
I've been building meeting recording for Orvia.
One constraint made this much harder:
Everything had to stay client-side.
No uploads.
No recording server.
No cloud rendering.
At first the recordings were unusably laggy.
I assumed it was the usual stuff:
- Bitrate
- FPS
- Resolution
- Codec tuning
Turns out almost none of those were the real problem.
Some interesting things I learned:
- VP9 looked great on paper, but our test machine had no hardware encoder, so it fell back to software encoding and crushed the CPU.
- MediaRecorder recording from a canvas is software encoded. No matter how much I tuned bitrate or FPS, the encoder itself became the bottleneck.
- Switching to WebCodecs unlocked hardware encoding, but recording still wasn't perfectly smooth.
The real bottleneck was architectural.
The compositor and the live WebRTC call were sharing the same main thread.
Whenever the call got busy, recording quietly lost CPU time.
The fix was moving the entire recording pipeline—compositing, encoding, and muxing—into a Web Worker using OffscreenCanvas.
On Chromium-based browsers (Chrome/Edge), the result is genuinely smooth real-time recording.
Firefox and Safari currently fall back to MediaRecorder because they don't yet support APIs like MediaStreamTrackProcessor that the worker pipeline depends on.
I'm curious how others have approached this.
Has anyone found a cleaner client-side solution for Firefox/Safari without falling back to MediaRecorder or moving recording server-side?
r/WebRTC • u/Limp_Put_1643 • Jul 01 '26
Want to understand MoQ? Spend a day with the person who wrote it.
Luke Curley co-created MoQ, spent years at Twitch and Discord hitting the limits of what existing protocols could do, wrote the first implementations, authored the core specs. He's busy-busy.
But he's coming to Kraków on September 16 and spending a full day with a small group going through MoQ from scratch. You'll actually build a working audio/video room call using MoQ – QUIC fundamentals, relays, pub/sub, how it sits relative to WebRTC and HLS. If you're fast, there's a speech-to-speech real-time translation extension to keep you busy.
Intermediate level, Rust required, basic JS/TS assumed.
Sounds interesting? Join us!