The C++ Media Stack
WebRTC, FFmpeg, and async networking in one toolkit. No Google monolith. No dependency hell. No fighting three build systems to get a frame on screen.
// The core of a WebRTC media server PacketStream stream; stream.attachSource(capture.get()); stream.attach(&session->media().videoSender(), 5); stream.start();
LibSourcey is the connective tissue: a modular C++20 toolkit that unifies FFmpeg, libuv, OpenSSL, and libdatachannel into a single composable pipeline. Capture, encode, transport, signalling, and relay. All dependencies managed via CMake FetchContent. Builds in minutes.
Documentation | Changelog | Contributing | LGPL-2.1+
Why LibSourcey
| libWebRTC (Google) | libdatachannel | GStreamer | LibSourcey | |
|---|---|---|---|---|
| Build system | GN/Ninja | CMake | Meson | CMake |
| Build time | Hours | Minutes | 30+ min | Minutes |
| Binary size | 50MB+ | Small | Large | Small |
| SSL | BoringSSL (conflicts) | OpenSSL | OpenSSL | OpenSSL |
| Media codecs | Bundled | None | GObject plugins | FFmpeg (any codec) |
| Capture/encode | Included | No | Plugin pipeline | PacketStream pipeline |
| Signalling | No | No | No | Symple (built-in) |
| TURN server | No | No | No | RFC 5766 (built-in) |
| Language | C++ | C++17 | C/GObject | C++20 |
libdatachannel gives you the WebRTC transport pipe. LibSourcey gives you the pipe, the water, and the faucet.
Architecture
Everything flows through PacketStream. Plug in a source, chain processors, attach a sink. The pipeline handles backpressure, frame dropping, and teardown so you don't. Nothing runs that you didn't ask for.
┌─────────────────────────────────────────────────────────────────┐
│ PacketStream │
│ │
│ ┌──────────┐ ┌──────────────┐ ┌───────────────────────┐ │
│ │ Source │───▶│ Processor │───▶│ Sink │ │
│ │ │ │ │ │ │ │
│ │ Camera │ │ FFmpeg H.264 │ │ WebRTC Track Sender │ │
│ │ File │ │ Opus encode │ │ Network socket │ │
│ │ Network │ │ OpenCV │ │ File recorder │ │
│ │ Device │ │ Custom │ │ HTTP response │ │
│ └──────────┘ └──────────────┘ └───────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
WebRTC send path:
MediaCapture → VideoEncoder → WebRtcTrackSender → [libdatachannel]
│
Browser ◀── RTP/SRTP ◀── DTLS ◀── ICE (libjuice) ◀───┘
│
LibSourcey TURN server
(relay for symmetric NATs)
WebRTC receive path:
[libdatachannel] → WebRtcTrackReceiver → FFmpeg decode → file/display
│
└─── ICE → DTLS → SRTP decrypt → RTP depacketise → raw frames
Signalling (Symple v4):
C++ server/client ◀──── WebSocket ────▶ Browser (symple-client-player)
Auth, presence, rooms, call protocol (init/accept/offer/answer/candidate)
Camera to browser in 150 lines. Browser to file in 130. The pipeline handles the plumbing.
What You Can Build
Stream a webcam to any browser
150 lines of C++. Camera capture, H.264 encoding, WebRTC transport, Symple signalling. Open a browser, see video. No plugins, no Google, no pain.
// Accept call, wire up the pipeline, stream session.IncomingCall += [&](const std::string& peerId) { session.accept(); }; session.StateChanged += [&](wrtc::PeerSession::State state) { if (state == wrtc::PeerSession::State::Active) { stream.attachSource(capture.get()); stream.attach(&session->media().videoSender(), 5); stream.start(); } };
See src/webrtc/samples/webcam-streamer/ or read WebRTC in 150 Lines of C++.
Record a browser's camera server-side
Browser sends WebRTC, your C++ server decodes with FFmpeg, writes to any format. Video depositions, telehealth recording, proctoring - server-side recording without cloud vendor lock-in.
See src/webrtc/samples/media-recorder/.
Stream any video file to a browser
Feed an MP4 in, get a real-time WebRTC stream out. Data channel for seek commands. Build your own streaming service.
See src/webrtc/samples/file-streamer/.
Run your own TURN relay
Production-grade RFC 5766 TURN server with channel binding and TCP support. Stop paying for hosted TURN. ~30% of real-world WebRTC connections need relay through symmetric NATs; this handles them.
See src/turn/samples/turnserver/.
HTTP that outperforms Go
72,000 req/s with keep-alive on a single-core micro VM. Built on the same libuv + llhttp that powers Node.js, minus the runtime, GC, and language bridge.
| Server | Req/sec | Latency |
|---|---|---|
| Raw libuv+llhttp | 96,088 | 1.04ms |
| LibSourcey | 72,209 | 1.43ms |
| Go 1.25 net/http | 53,878 | 2.31ms |
| Node.js v20 | 45,514 | 3.56ms |
LibSourcey delivers 75% of raw libuv throughput while providing a complete HTTP stack (connection management, header construction, WebSocket upgrade, streaming responses). It outperforms Go's net/http by 34% and Node.js by 59%. All three share the same foundation (libuv for async IO, llhttp for HTTP parsing); the difference is pure runtime overhead.
See src/http/samples/httpbenchmark/ for methodology.
Quick Start
Requirements
| Platform | Compiler |
|---|---|
| Linux | GCC 12+ or Clang 15+ |
| macOS | AppleClang 15+ (Xcode 15+) |
| Windows | MSVC 2022 (Visual Studio 17+) |
CMake 3.21+ and pkg-config (Linux/macOS) required. Everything else is fetched automatically:
| Dependency | Version |
|---|---|
| libuv | 1.50 |
| llhttp | 9.2.1 |
| OpenSSL | 3.x |
| nlohmann/json | 3.11.3 |
| zlib | 1.3.1 |
Optional: FFmpeg 5+/6+/7+ (-DWITH_FFMPEG=ON), OpenCV 3.0+ (-DWITH_OPENCV=ON), libdatachannel (-DWITH_LIBDATACHANNEL=ON).
Build from source
git clone https://github.com/sourcey/libsourcey.git cd libsourcey cmake -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=ON cmake --build build --parallel $(nproc) ctest --test-dir build --output-on-failure
CMake FetchContent
include(FetchContent) FetchContent_Declare(libsourcey GIT_REPOSITORY https://github.com/sourcey/libsourcey.git GIT_TAG v2.1.0 ) FetchContent_MakeAvailable(libsourcey) target_link_libraries(myapp PRIVATE scy_base scy_net scy_http)
find_package
After installing (cmake --install build):
find_package(LibSourcey REQUIRED) target_link_libraries(myapp PRIVATE scy_base scy_net scy_http)
Code Examples
Media pipeline
Camera to encoder to network:
PacketStream stream; stream.attachSource(videoCapture); stream.attach(new av::MultiplexPacketEncoder(opts), 5); stream.attach(socket, 10); stream.start();
HTTP server
http::Server srv{ "127.0.0.1", 1337 };
srv.Connection += [](http::ServerConnection::Ptr conn) {
conn->Payload += [](http::ServerConnection& conn, const MutableBuffer& buffer) {
conn.send(bufferCast<const char*>(buffer), buffer.size());
conn.close();
};
};
srv.start();WebRTC peer session
wrtc::PeerSession::Config config; config.rtcConfig.iceServers.emplace_back("stun:stun.l.google.com:19302"); config.mediaOpts.videoCodec = av::VideoCodec("H264", "libx264", 1280, 720, 30); wrtc::SympleSignaller signaller(client); wrtc::PeerSession session(signaller, config); session.IncomingCall += [&](const std::string& peerId) { session.accept(); }; session.StateChanged += [&](wrtc::PeerSession::State state) { if (state == wrtc::PeerSession::State::Active) startStreaming(session); };
Modules
14 modules. Include only what you need; dependencies resolve automatically.
| Module | What it does |
|---|---|
| base | Event loop (libuv), signals, streams, logging, filesystem, timers |
| crypto | Hashing, HMAC, RSA, X509 (OpenSSL 3.x) |
| net | TCP, SSL/TLS, UDP sockets, DNS |
| http | HTTP server/client, WebSocket, cookies, streaming, keep-alive |
| json | JSON serialisation (nlohmann/json) |
| av | FFmpeg capture, encode, decode, record, stream (FFmpeg 5/6/7) |
| symple | Real-time messaging, presence, rooms, WebRTC call signalling |
| stun | RFC 5389 STUN for NAT traversal |
| turn | RFC 5766 TURN relay server |
| webrtc | WebRTC via libdatachannel: media bridge, peer sessions, codec negotiation |
| archo | ZIP/archive handling |
| pluga | Plugin system (shared library loading) |
| pacm | Package manager for plugin distribution |
| sched | Task scheduler for deferred/periodic jobs |
Contributors
- Kam Low (@auscaster) - Creator and primary developer
- Sergey Parfenyuk (@sparfenyuk) - macOS compile fixes, type corrections, buffer handling
- Yury Shubin (@yuryshubin) - iOS build toolchain and platform fixes
- Norm Ovenseri (@normano) - Apple/FFmpeg builds, AVFoundation support, verbose logging
- Igor Lutsyk (@lutsykigor) - WebRTC/WebSocket fixes, OpenCV+WebRTC sample app, Firefox compatibility
- Kryton (@Malesio) - Segfault fixes and Valgrind cleanup
- Vinci Xu (@VinciShark) - Windows documentation, testing and updates
- Michael Fig (@michael-fig) - Compiler flags for building without FFmpeg
- Stanislav Kapulkin (@kapulkin) - WebRTC modernisation and macOS compile definitions
- Thomas Reichhart (@blackforest-tom) - FFmpeg constant updates and ARM build fixes
- Artem Suprunov (@artemiuzzz) - WebRTC null pointer fix and library path resolution
- Hyunuk Kim (@surinkim) - Windows
std::codecvtunicode conversion fix - Cameron Smith (@cksmith) - Git line ending normalisation
- Damian Zelim (@ZelimDamian) - OS X compiler flag fixes
- Alexey (@deilos) - Cross-platform FFmpeg build script fixes
Contributing
PRs welcome. See the contributing guide for code style, tests, and workflow.