All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- Added
MediaCapture::setOpenTimeoutUsec()and interruptible FFmpeg network opens so blocking RTSP and other network sources can time out or stop cleanly instead of hanging shutdown. - Added default FFmpeg protocol allowlists and network-open timeout handling for
MediaCapture, while still allowing callers to override the underlying AVOptions. - Added
http::Server::setWebSocketOriginValidator()and Symple server origin policy options (enforceOrigin,allowSameOrigin,originScheme, andallowedOrigins) so browser WebSocket upgrades can be rejected before the101handshake. - Added a move-based TURN request path for parsed STUN messages, avoiding deep copies of inbound attributes and data payloads in server receive loops.
symple::Server::Options::maxConnectionsnow defaults to1024instead of unlimited, matching the hardened production defaults used by the server responder.- Logging macros now check a process-wide atomic level filter before constructing
LogStreamobjects or evaluating log arguments, making filtered log sites substantially cheaper and preventing side effects in disabled log arguments. - STUN transaction IDs are now generated lazily for outbound messages, avoiding unnecessary entropy work on inbound parse paths.
- TCP peer addresses are cached at connect time so repeated peer-address lookups do not call back into libuv for stable connection metadata.
- The pacm submodule was advanced to the latest hardened revision used by the control-surface defaults.
- Hardened base lifetime primitives across signals, queues, packet streams, synchronizers, timers, handles, threads, runners, and
TaskRunnerso shutdown and task execution remain ownership-safe under concurrent teardown. - Hardened socket and HTTP handling, including address validation, adapter lifetime, SSL flush behavior, URL parsing, and WebSocket frame size checks.
- Fixed FFmpeg ownership and media-state consistency issues in audio resampling, video contexts, media capture, video conversion, and WebRTC media bridging.
- TURN clients and samples now verify message integrity by default and avoid logging credentials.
- WebRTC track receiver teardown is now safe against libdatachannel callbacks that are still in flight while the receiver is being destroyed.
- Hardened parsing and memory-safety checks across zip extraction, Base64, crypto, X.509 certificates, STUN attributes/messages, Symple command handling, WebRTC codec selection, remote media planning, and the pipeline C API.
- Stabilized the WebRTC session test harness after the teardown and callback lifetime hardening.
- Removed stale pluga references and fixed sample/package-manager rot found during the hardening pass.
- Added a
webrtc/samples/whip-receiversample that accepts WHIP publishers over HTTP or HTTPS, supports optional bearer-token auth and client ICEPATCH, records H.264/Opus sessions to MP4, and includes FFmpeg/OBS usage docs plus a local certificate helper. - Added the
icey-sysandiceyRust crates, including safe Rust wrappers for the initial RTSP-to-browser pipeline surface and a crate-level example. - Added the
icey::pipeline_capihost C API surface for creating, configuring, starting, stopping, and destroying an opaque WebRTC pipeline from foreign-language bindings. - Extended
graftwith host-surface ABI support, including thehostruntime kind, host manifest validation, and documented conventions for exported C function tables.
- Windows shared-library builds now export the
icy::avmedia packet hierarchy andVideoConverterwithAV_API, fixing MSVC DLL link failures when downstreamvisioncode usesavtypes across module boundaries. This lets Conan Center consume a clean post-2.4.10 source release without its Windows shared-build patch. - Alpine packaging and its container validation helper now install
nlohmann-json, matching the system-dependency CMake package exported by icey. MultiplexEncodernow tracks audio and video PTS independently, preventing muxed audio/video output from dropping valid interleaved packets as duplicate or backward timestamps.AudioEncodernow advances its buffered output PTS when frames are submitted to delayed encoders such as AAC, avoiding duplicate DTS packets during MP4 recording.
- API docs and module guides were regenerated and expanded for the new graft host-surface and pipeline API work.
- The docs toolchain now uses the published Sourcey package and includes the Sourcey C++ quality gate used by CI.
- Package-manager publishing now targets the shared Homebrew tap configuration used by the install docs.
- Removed the unused
Base64PacketEncoderpacket-stream adapter and its public header. Use theicy::base64namespace helpers directly for Base64 encoding and decoding.
ICapture::start/::stop(which overridebasic::Startable) andMediaCapture::emit(which overridesPacketSource::emit) are now declared withoverride. clang-18 with-Werror -Winconsistent-missing-overridewas failing the bench build on these.[[nodiscard]]returns fromAudioEncoder::encode,VideoEncoder::encode,MultiplexEncoder::encode{Video,Audio}, andVideoEncoder::flushare now explicitly discarded with(void)at the seven call sites inaudiopacketencoder.cpp,multiplexpacketencoder.cpp,videoencoder.cpp, andvideopacketencoder.cpp. Emission happens through the encoder's emitter, not through the boolean return; the discard was always intentional.
- The CI benchmarks job now runs under clang-18 instead of gcc-14. The gcc-14 build of the bench binaries hit SIGILL on the GitHub-hosted ubuntu-24.04 runner under
-O3; the library itself builds and tests cleanly under gcc-14 in the regular Linux job and under all three sanitizer jobs. Tracked by nilstate/icey#325.icy_add_benchmarkcarries a-O2 -fno-tree-vectorizeGCC fallback as defence in depth for anyone building bench binaries with GCC outside CI. - Doc cross-links to the removed
docs/build/*pages now redirect to therecipes/http-serverrecipe, the README quick-start, anddocs/run/install.sourcey.config.ts,release-sync.sh, andrelease-check.shno longer iterate over the deleted files.
wrtc::codec_registry::hasEncodernow does a runtime probe (avcodec_alloc_context3+avcodec_open2), with results cached. The prior implementation only checkedavcodec_find_encoder_by_name, which on Linux distros that ship libavcodec with hardware-encoder wrappers built in (h264_nvenc, h264_vaapi, h264_qsv) returned true even when the runtime resources for those encoders (CUDA, VA-API drivers, etc.) were absent. The h264-on-macOS / videotoolbox path was unaffected; the fix prevents codec selection from picking a hardware encoder that exists at link time but cannot be opened at runtime, which surfaced as "Cannot open the video codec: Operation not permitted" in the icey-cli browser smoke on Linux CI.
http::Serverportability: replacedfile_clock::to_syswith the standard delta-calibration idiom (system_clock::now() + (fileTime - file_clock::now())). MSVC's_File_time_clockdoes not exposeto_sys, so the prior libc++-targeted fix from 2.4.6 broke the Windows build. The new form works on libstdc++, libc++, and MSVC, and tolerates the precision difference between libc++ and libstdc++ that the priortime_point_castwas meant to address.parseDeviceUrl: device-resolution path is now guarded byHAVE_FFMPEG_AVDEVICE. The 2.4.7 implementation calledavdevice_register_allunconditionally, breaking builds where libavdevice is not linked. Without it, hitting a recognised device URL throws an explicit "libavdevice is not linked" error rather than failing to build.
- Doc cleanup: cross-links to the removed
docs/build/*pages are redirected to therecipes/http-serverrecipe, the README quick-start, anddocs/run/install.sourcey.config.ts,release-sync.sh, andrelease-check.shno longer iterate over the deleted files.
icy::av::parseDeviceUrl(source)— single source of truth for libavdevice URL schemes (avfoundation:,v4l2:,dshow:). Returns the resolvedAVInputFormat*and the post-prefix filename. Throws if a recognised scheme has no matching backend on this build.MediaCapture::openFileroutes recognised device URLs through the existingopenStream(filename, iformat, opts)path, so callers can open the OS camera directly without an ffmpeg/relay subprocess.
internal::init()now callsavdevice_register_all()underHAVE_FFMPEG_AVDEVICE. The prior comment was wrong: codec/format auto-registration arrived in FFmpeg 4.0+, but libavdevice still requires an explicit register call forav_find_input_format("avfoundation"|"v4l2"|"dshow")to resolve.parseDeviceUrlalso performs a one-shotstd::call_onceregistration so device URLs work even before anyMediaCaptureis constructed.MediaCapture::runno longer treatsAVERROR(EAGAIN)fromav_read_frameas fatal. Live demuxers (notably avfoundation) return it whenever their internal frame queue is momentarily empty; the prior code tore the capture down at the first hiccup, which surfaced as the capture pipeline emitting only the initial three buffered frames before going silent.
- Bumped the pinned
libdatachannelfromv0.24.1tov0.24.2.
http::Servernow compiles on macOS libc++ wherefile_clock::to_sysreturns a different precision than libstdc++ on Linux. Wrapped intime_point_cast<system_clock::duration>so both stdlibs produce asystem_clock::time_pointcleanly.AudioPacketEncoder::onStreamStateChangenow callsAudioEncoder::open()aftercreate()so the resampler is built when input format differs from the encoder's expected format. Without it, AAC's planarfltpwas being written to opus's interleavedfltFIFO, producing garbled audio with mis-interleaved channels.AudioEncoder::flushBufferno longer increments output PTS by 1 per frame. PTS is now anchored to the first input packet's PTS and advances byframe->nb_samplesper encoded frame, matching the standard pattern that libopus and other audio encoders expect. Eliminates the[libopus] Queue input is backward in timeflood.
MediaCapture::setOpenOptions(map<string, string>)for passing libavformat AVOptions (rtsp_transport,fflags,analyzeduration,probesize,low_delay,reorder_queue_size, ...) atopenFile()time. Used by callers handling live network sources that need low-latency hints.
- System-dependency builds no longer vendor and install
nlohmann/json.hpp, avoiding conflicts with downstream package managers that already providenlohmann-json - Exported CMake package configs now propagate the
nlohmann_jsondependency when system deps are enabled
- Realtime intelligence pipeline primitives in the
visionmodule, including frame normalization for detector-ready frames - WebRTC receive jitter buffer for smoother inbound media playback
- API reference docs for graft, speech, and vision modules
- Markdown sanitization script for generated API docs
- Permanent macOS system-deps + FFmpeg CI coverage matching downstream package-manager builds
- Doxygen config updated for new module coverage
- Docs now use latest sourcey toolchain
- Module guide updated with graft, speech, vision entries
- pluga module and docs (replaced by graft)
- Apple AVFoundation source compatibility for package-manager builds on modern macOS SDKs
- Darwin shared-library symbols are preserved for downstream package-manager builds
- Downstream package-manager builds now resolve
libuvcorrectly when the system dependency is exported as a shared target instead of a static-only alias - RPM source-package staging now carries the downstream compatibility patch set and claims the installed umbrella and vendored JSON headers in the development package
- MacPorts builds now force the supported
ReleaseCMake build type instead of inheriting the unsupported default from the port group - The GitHub release workflow now validates the pre-finalize tag state, so tagged releases can publish before
make release-finalizepins the archive hashes onmain
- Package-manager builds now accept the shared
libuv::uvtarget exported byvcpkgand other system package layouts - Windows consumers no longer rely on backported export/linkage fixes for
Timeout,PacketFactory,Transaction, and the baseuvwrapper templates - FFmpeg-backed builds now propagate discovered library search directories so Windows link steps can resolve
avcodec.liband related FFmpeg libraries
- Release tooling now treats Conan like the rest of the package-manager surfaces:
make releaseseedspackaging/conan/conandata.ymlmake release-finalizepins the tagged archive hash and runs the final consistency check
- The documented release flow is now explicit about the post-tag finalize step instead of suggesting a pre-tag
release-checkthat could only fail on placeholder hashes
- Alpine system-package builds now accept the shared
llhttptargets exported by Alpine'sllhttp-devpackage instead of hard-linkingllhttp_static - The local Conan recipe now builds from immutable tagged GitHub archives instead of exporting a live checkout into the package
- Repo-local package manager layouts under
packaging/withmake package-conanandmake package-vcpkgentry points for local consumer validation - Homebrew tap formulae, Debian / PPA source-package scaffolding, and release hooks for those package surfaces
- Browser smoke coverage for the
src/webrtc/apps/media-server/web/frontend and media-server interop path - Reportable microbenchmark runner plus focused parse/probe benches for packet stream, HTTP, WebSocket, and STUN hot paths
- Focused
webrtcbenchandsymplebenchtargets covering:- WebRTC sender dispatch
- WebRTC receiver dispatch
- Symple room fanout
- Symple client parse/dispatch
- API overview quality checks in the docs toolchain to catch shallow or missing generated reference summaries
- Internal Symple protocol/state helpers for welcome parsing, sanitized presence emission, room reconciliation, and roster presence application, backed by focused unit coverage
webrtc_supportas a dedicated support library for Symple/WebSocket signallers, including the server-side virtual-peer adapter now used by samples andmedia-server
- WebRTC browser/media-server behavior after 2.3.0: codec negotiation is tighter, browser offer handling is stricter, and
PeerSession/ track flow is more defensive under real browser traffic - Public package, docs, and sample surface now use lowercase
iceyconsistently, with no retainedIceyCMake/package-manager naming - Public lifecycle verbs are now standardized on
start()/stop()across HTTP client/server, Symple client/server, and TURN client surfaces; the previous spellings were removed instead of being kept as compatibility aliases - WebRTC internals are now cut along explicit seams instead of monolithic translation units:
PeerSessionstate/signalling/RTC work is split acrosspeersession.cpp,peersessionsignalling.cpp, andpeersessionrtc.cpp- remote answer scoping lives in
remotemediaplan.cpp - codec support is centralized in
codecregistry.cpp media-serverruntime code is split underapps/media-server/internal/
- Public Symple and TURN configuration handoff now favors value-style option snapshots instead of live mutable option bags
- Public option mutation is now explicit on package-manager surfaces via
mutableOptions(), while the public AV encoder interfaces expose const option views PeerSession::Confignow exposes media settings underconfig.media, and answer-session media options are derived explicitly from the remote offer's mids, directions, and payload types instead of relying on looser implicit defaults- Symple client/server internals are now organized under
src/symple/src/client/andsrc/symple/src/server/, with shared wire helpers insrc/symple/src/protocol.* - API reference coverage has been deepened across the core modules, WebRTC, and the pacm/pluga surfaces, with reorganized Sourcey guides and workflows
- icey docs now consume published
moxygen/sourceynpm releases instead of git-pinned or exact-pinned toolchain versions - Packaging assets are centralized under
packaging/instead of spreading Conan and vcpkg files across the repo root - Installed
icey.pcmetadata now uses the current package-manager-facing description instead of the old networking-only tagline - Browser support claims are now explicit:
- Chromium and Firefox are validated by the committed Playwright smoke
- Playwright WebKit on Linux is treated as non-authoritative for Safari/WebRTC publish-path claims
- Exported CMake package consumers now tolerate dependency target-name differences across FetchContent, Conan, and vcpkg installs
- Repo-local Conan and vcpkg packaging validation now passes sequentially, and installed
icey.hheaders no longer leak absolute build/source paths - Browser media-server smoke harness failures and related WebRTC sample pipeline regressions that were blocking stricter interop coverage
- Symple-backed WebRTC signalling now enforces full
user|idpeer identity on the public call boundary instead of accepting ambiguous bare user/session forms - WebRTC receive-side codec detection no longer stringifies track descriptions back into SDP just to rediscover codec/clock data on bind or record paths
- Symple clients now transition cleanly to
Erroron underlying transport failures, including initial WebSocket connect failures, via explicithttp::ClientConnectionerror propagation - pacm JSON handling in the submodule update path, keeping the external package-manager surface aligned with the current docs/API snapshots
- Dedicated protocol fuzz targets under
BUILD_FUZZERSfor the HTTP parser, WebSocket frame parser, STUN message parser, and TURN indication/request parsing - Build-tree and install-tree consumer validation for the exported CMake package surface
- Dedicated microbenchmark targets under
BUILD_BENCHMARKS:signalbench,httpbench,httpparsebench, andwsbench, plus the separateBUILD_PERFhttpperf/httpperf_comparewrk/Node.js/Go comparison harness - WebRTC loopback/media regression coverage for:
- data-channel roundtrip
- encoded H.264 roundtrip
- encoded Opus roundtrip
- relay audio fanout
- relay source handoff
media-serverrecordandrelaymodes are now real shipped behaviors rather than placeholder sample code
- HTTP benchmark assets moved out of
src/http/samples/httpbenchmark/intosrc/http/perf/, whilesrc/http/bench/now stays microbench-only andsrc/http/samples/contains samples only PacketStreamqueue retention and ownership semantics are now explicit at queue boundaries, with deterministic overload/drop accounting and synchronized multi-source passthroughPeerSessionnow uses explicit call phases and stricter signaling ordering, and WebRTC track setup requires explicit codec selection instead of fallback codec guessing- The canonical WebRTC send path used by the samples and
media-serveris now encode -> RTP packetize -> sender, with stable sender bindings across call lifecycles
- Core async lifetime handling in
base/net/http, including retained handle/request context, state-driven HTTP server lifecycle, and typed WebSocket parse errors - STUN/TURN protocol correctness and relay hot paths:
- correct STUN length/integrity patching
- correct plain vs XOR address handling
- IPv6 address attribute wire sizing
- binary/numeric TURN permission checks and local-IP policy
- Symple routing/state correctness:
- presence canonicalization
- room-based authz checks
- reconnect room restoration
- virtual-peer copy semantics
media-serverrelay/signaling behavior:- remote ICE candidates queue until remote SDP is installed
- relay source promotion/handoff works correctly
- stable media sender lifetime across attach/detach
- Package consumer discovery:
- exported targets work correctly from both the build tree and install tree
find_package(icey REQUIRED COMPONENTS ...)correctly marks built components as found
- Symple v4 server hardening: max connections, per-peer rate limiting (token bucket), max message size, graceful shutdown broadcast with error responses (413/429/503)
- Team/group permission scoping: rooms as permission boundaries,
roomsfield in auth message,Authenticatesignal passes mutableroomsvector for server-side assignment - Direct message permission check: sender and recipient must share at least one room
- Protocol version in welcome message (
"protocol": "symple/4") and room list in welcome response - ASAN CMake support:
-fsanitize=addresspropagates to FetchContent C dependencies viaCMAKE_C_FLAGS http::Serveroverloads acceptingnet::TCPSocket::Ptrfor TLS/SSL support alongsideuv::Loop*constructorssmpl::Serveracceptsuv::Loop*parameter, threads loop through tohttp::Server- Timer destructor calls
stop(), timer callback null-checksreq->data(defense-in-depth) Peer::operator=with explicitstatic_cast<const json::Value&>(avoids nlohmann template overload)- Symple module README with server, client, WebRTC signalling, and permissions documentation
- 4 hardening tests: max connections, max message size, rate limiting, graceful shutdown
- Mutex deadlock in
Responder::onPayload:connection().close()for close/auth-reject was called inside the lock; moved toshouldCloseflag pattern outside lock scope - Use-after-free in
Server::onConnectionClose: non-pooled connections were destroyed synchronously during their own callback chain; now deferred via idle callback (found by ASAN) expect()macro silently skipped side effects inNDEBUGmode:waitFor()calls insideexpect()were never executed in Release builds
http::Serverprimary constructor takesuv::Loop*instead ofnet::TCPSocket::Ptr; loop is stored as_loopmember, used in shutdown and deferred destruction- SympleSignaller and all WebRTC samples updated from
smpl::TCPClient/SSLClienttosmpl::Client
socketiomodule deleted entirely (replaced by Symple v4 native WebSocket protocol)- All
socketioreferences removed from CMakeLists.txt across symple, webrtc samples
- WebRTC module with libdatachannel integration (no Google libwebrtc dependency)
- Three-layer architecture: track factories (layer 1), per-track PacketStream adapters (layer 2), MediaBridge + PeerSession convenience wrappers (layer 3)
- Transport-agnostic
SignallingInterfaceabstract base class; PeerSession no longer depends on Symple SympleSignaller: Symple call protocol implementation (call:init/accept/reject/offer/answer/candidate/hangup)- Four WebRTC sample applications: data-echo, webcam-streamer, file-streamer, media-recorder
CodecNegotiatormaps RTP codecs to FFmpeg encoders at runtime- CI job for WebRTC builds (Ubuntu 24.04, gcc-14, FFmpeg + OpenSSL + libdatachannel)
- Symple v4 protocol: native WebSocket transport replacing Socket.IO (breaking change from v3)
- C++ Symple server: auth, rooms, routing, presence, shutdown lifecycle
- C++ Symple client: plain WebSocket, auth flow, reconnection, close guard
- Protocol spec (
PROTOCOL.md): connection lifecycle, message types, addressing, rooms, auth modes, scaling, v3-v4 migration - 14 integration tests (address, peer, message, presence, roster, server lifecycle, connect, two-peer presence, message routing, auth failure, disconnect presence)
test::waitFor()helper for event-driven async test patterns
ConnectionPool: LIFO stack reuses ServerConnection objects across requests (configurable max size, default 128)ServerConnection::reset(): swap sockets without reconstruction (zero-alloc steady state)DateCache: formatted Date header updated once per second via timer- HTTP/1.1 keep-alive: persistent connections, parser resets via
on_message_begin, idle timeout (default 30s) IntrusivePtr<T>andRefCounted<T>: intrusive smart pointer with non-atomic embedded refcount (zero allocation overhead vs shared_ptr)- Go net/http server added to benchmark suite for comparison
- Pre-formatted static status lines for common HTTP codes
USE_SYSTEM_DEPSCMake option for vcpkg/system package integration (switches FetchContent to find_package for libuv, llhttp, zlib, minizip)- Vendored nlohmann/json single header (v3.11.3), eliminating FetchContent download
- vcpkg port with full dependency manifest and feature flags
- Symplestreamer sample: camera/file video streaming to symple-player via MJPEG over WebSocket
- HTTP benchmark suite and performance section in README
SO_REUSEPORTsupport viaServer::setReusePort()for multicore HTTP servingNullSharedMutexandLocalSignalfor lock-free signal dispatch on single-threaded event loopsICY_DATA_DIRcompile definition for test/sample data paths
Handle::Contextchanged fromshared_ptrtounique_ptr(sole ownership, eliminates control block allocation per handle)Handle::Context::~Contextclearshandle->data = nullptrbeforeuv_closeto prevent use-after-free in pending callbacksStream::writecallback null-checkshandle->databefore accessing the Stream objecthttp::Server::shutdown()defers connection destruction viauv_idlecallback (prevents write callback use-after-free)smpl::Server::shutdown()uses_shuttingDownatomic flag to guard Responder callbacks during destructionsmpl::Client::close()uses_closingguard to prevent re-entrant close- Symple client no longer depends on socketio module; uses native WebSocket via HTTP module
- WebRTC module
DEPENDSdrops symple (signalling is transport-agnostic) SKIP_EXPORToption added toicy_add_modulefor FetchContent dependency conflicts- README rewritten: WebRTC hero example, comparison table vs libWebRTC/libdatachannel/GStreamer/Pion, architecture diagram, module table
- Conan recipe added with per-module components and optional FFmpeg/OpenCV features
std::endlreplaced with'\n'throughout (removes redundant flush from logger macros)std::bindreplaced with lambdas throughout- Iterator loops converted to range-based for with structured bindings
typedefconverted tousingaliasesoverrideadded to virtual methods in derived classesstring_view: converted ~270 read-onlyconst std::string¶meters across base, http, crypto, net, symple, av, json, stun, turn modulesrandom: rewrote PRNG withstd::mt19937+std::random_device, replacing BSD nonlinear additive feedback LFSRdatetime: rewrote internals with C++20std::chronocalendar types (year_month_day,sys_days,weekday), replacing Julian Day floating-point mathnumeric: rewrote sprintf-based number formatting withstd::to_chars, consolidated 50 functions into shared templatesutil: replaced 10icomparetemplate overloads (~140 lines) with singlestring_viewimplementation- Renamed
json::valuetojson::Valuefor codebase consistency - HTTP server connections container changed from
vectortounordered_mapfor O(1) lookup - Single-pass response header assembly with pre-computed reserve
- All net/http signals switched to
LocalSignal, eliminating mutex acquisition per emit uv_write_trequest pooling via freelist in Stream (avoids heap alloc per write)- Static status code string lookup in
Response::write - Cached peer address after connect (avoids repeated
uv_tcp_getpeernamecalls) - Modernised all sample applications
- Moved test data (
test.mp4) to top-leveldata/directory shared across modules - Refreshed README with contributors section, moved build/contributing docs to
docs/
sendHeader()undefined behavior: response buffer moved from local to member (localstd::stringwas freed before asyncuv_writecompleted)UV_EOFinStream::handleRead()now triggers graceful close instead of error state- Symple v4 client
Peerto json assignment neededstatic_cast<const json::Value&>to avoid nlohmanntype_error.302 -Werrorenabled in CI; fixed all remaining compiler warningsjson::findNestedObjectWithPropertywas comparingit.value()instead ofit.key()Configuration::removeAlliterator invalidationLogStreamstub destructor forENABLE_LOGGING=OFFbuildshttpclientsampleStatusCodeenum streaming
- WebRTC hard dependency on Symple (signalling is now pluggable via
SignallingInterface) - Stale
bench/directory (duplicate ofsrc/http/samples/httpbenchmark) - Dead commented-out JsonCpp stringify code in json module
- Empty
json.cppstub - Deprecated
thread.h/thread.cppandarchotest file - In-source build artifacts
Keep-alive benchmark results (single vCPU, wrk -t4 -c100 -d10s):
| Server | req/s | Latency |
|---|---|---|
| Raw libuv+llhttp | 96,088 | 1.04ms |
| icey | 72,209 | 1.43ms |
| Go 1.25 net/http | 53,878 | 2.31ms |
| Node.js v20 | 45,514 | 3.56ms |
- macOS build: added missing
<unistd.h>and<cstdio>includes in platform.cpp - Windows build: added missing
<ostream>include in error.h (MSVC string_view needs full definition) - Windows build: replaced
SIGKILLwithSIGTERMin process.h (SIGKILL not defined on MSVC) - Windows build: added
<csignal>to application.cpp and process.h - macOS linker: removed unnecessary
-ldlfrom Apple config in icey.cmake - CI: fixed sanitizer env var syntax (split matrix.env into env_name/env_value)
- CI: removed ccache from coverage job (incompatible with gcov instrumentation)
- CI: added
submodules: recursiveto all checkout steps - CI: added
BUILD_APPLICATIONS=OFFto all jobs - pacm: fixed apps/CMakeLists.txt referencing
pacmconsoleinstead ofpacm-cli - Windows build: added missing
<windows.h>include in filesystem.cpp - Windows build: fixed winsock.h/winsock2.h include order conflict in x509certificate.cpp
- Windows build: added zlib include path for minizip in archo module
- Windows CI: fixed ctest syntax (
--config->-C Release)
-
Removed 7 dead
#if 0code blocks (packetstream.cpp, cipher.cpp, turn tests, deprecated thread.h) -
Cleaned up 11 stale TODO/FIXME comments in samples and deprecated code
-
Replaced all
assert()calls in production code with exceptions or early returns (40+ occurrences) -
Removed all
_WIN32_WCE(Windows CE) compatibility code -
Standardised Windows platform guard from
WIN32to_WIN32 -
Fixed
conston value return types in buffer.h (12 compiler warnings) -
Added
[[fallthrough]]annotations to base64.cpp switch cases (5 warnings) -
Added
overrideto Thread::start() and AsyncLogWriter::run() -
Fixed Thread template constructor init order warning (two-phase init)
-
Zero compiler warnings in project code (excluding third-party deps)
- Cross-platform process test (spawn echo, capture stdout, verify exit code)
- AV test data integrity verification: codec, sample rate, channel count, and duration checks via avformat
- SSL hostname verification integration test (connects to google.com with certificate verification enabled)
- Rewrote CMake build system with modern target-based dependencies and
icy_add_module()pattern - Replaced vendored sources with CMake FetchContent (libuv, zlib, llhttp, nlohmann/json)
- CMake 3.21 minimum, with proper
find_package(icey)and FetchContent consumer support - CPack packaging support (deb, rpm, tar.gz)
- External module plugin pattern for out-of-tree modules
- Multi-stage Docker build on Ubuntu 24.04 LTS
- GitHub Actions CI replacing CircleCI (Linux GCC/Clang, macOS AppleClang, Windows MSVC)
- CI includes address/undefined sanitizers and code coverage
.clang-formatand.clang-tidyconfigurations added
- C++20 minimum standard (from C++14)
#pragma oncereplaces include guards throughoutusingtype aliases replacetypedefnullptrreplacesNULLenum classreplaces unscoped enums- Smart pointers (unique_ptr, shared_ptr) throughout; RAII wrappers for OpenSSL, FFmpeg, and logger resources
std::chronoreplacesclock_ttiming[[nodiscard]]on key return values (crypto, net, av, archo modules)noexcepton all destructorsstd::invoke_resultreplaces deprecatedstd::result_of- C-style casts replaced with
static_cast/reinterpret_cast - Entire codebase formatted with clang-format
- OpenSSL 3.x migration (new provider/context APIs, deprecated function replacements)
- FFmpeg 6.x/7.x migration (avcodec send/receive API, codecpar, channel layouts,
av_*iterators) - llhttp replaces http_parser for HTTP/1.x parsing
- nlohmann/json replaces JsonCpp
- libuv 1.50 compatibility (accessor APIs, proper handle close, loop alive checks)
- FindOpenCV.cmake rewritten for OpenCV 4.x
- pacm: Default checksum algorithm changed from MD5 to SHA256
- pacm: SSL certificate verification enabled (was
initNoVerifyClient) - pacm: Path traversal protection added to zip extraction and package metadata
- pacm: Default API endpoint changed from http to https
- net: SSL hostname verification via
SSL_set1_host(), auto-wired throughSSLSocket::connect(host, port) - net: TLS 1.2 enforced as minimum protocol version
- net: ALPN protocol negotiation support (
SSLContext::setALPNProtocols) - net: SNI support (
SSLContext::enableSNI)
- STUN: ChannelNumber attribute factory was creating wrong type (ICEUseCandidate instead)
- STUN: Bit shift undefined behavior in UInt32/UInt64Attribute::setBit
- TURN: Permission lifetime corrected to RFC 5766-mandated 5 minutes (was 3)
- TURN: Server::stop() null pointer dereference when sockets not configured
- archo: ZipFile::closeCurrentFile() was calling unzOpenCurrentFile instead of unzCloseCurrentFile
- archo: Compressed/uncompressed file size fields were swapped
- base: once.h missing uv_close() on prepare handle (resource leak)
- base: UV_EOF in Stream::handleRead() now triggers graceful close instead of error state (fixes shutdown() causing spurious errors)
- base: IPC waitForSync() now has configurable timeout (default 5s) preventing infinite hangs
- base: Signal slot ID uniqueness enforced, throws on collision
- base: DateTime constructor/assign validate all components at runtime (was assert-only)
- base: PacketStream destructor warns instead of asserting on non-terminal state
- base: TaskRunner::add() fixed stray semicolon bug that allowed duplicate task insertion
- crypto: EVP_md5 replaced with EVP_sha256 for cipher key derivation
- av: MediaCapture::run() fixed stray semicolon on looping seek (was a no-op)
- av: MultiplexEncoder PTS tracking now mutex-protected across audio/video paths
- av: MediaCapture flags (_stopping, _looping, etc.) changed to std::atomic for thread safety
- av: FFmpeg 6.x const AVOutputFormat compatibility (removed oformat->codec assignment)
- av: Unchecked FFmpeg return values now checked: avformat_write_header, av_write_trailer, avio_close, avcodec_parameters_from_context
- http: Download progress tracking re-enabled via ClientConnection::IncomingProgress signal
- http: WebSocket RFC 6455 compliance: RSV bit validation, opcode validation, mask enforcement, ping/pong auto-response, close frame handshake
- http: WebSocket partial frame buffering across TCP segments
- http: WebSocket fragmentation/continuation frame support
- net: SSLContext min proto version was set before null check on context (crash fix)
- net: SSLAdapter SSL_ERROR_WANT_WRITE now calls flushWriteBIO instead of asserting
- pacm: latestSDKAsset() logic simplified (dead code branch removed)
- sched: Scheduler::update() and run() memory leaks fixed (erased tasks without deleting)
- All
assert()calls in production source code replaced with runtime checks (throws, returns, or warnings) - approximately 110+ asserts across 30 files in base, net, av, crypto, pacm modules - All stale
#if 0dead code blocks removed across 13+ source files - Stream::write() backpressure via configurable high water mark on libuv write queue (default 16MB)
- TaskRunner ownership modernised:
std::deque<std::unique_ptr<Task>>replaces raw pointer container
- util module merged into base (headers moved, includes updated, downstream deps fixed)
- archo module updated to use
std::filesystem::path - Socket.IO protocol v5 compatibility verified
- FindFFmpeg.cmake rewritten to use pkg-config (old version depended on deleted CMake macros)
- pacm and pluga modules fully modernised (noexcept destructors, dead code removed, typos fixed)
- base: Timer pause/resume, timer one-shot, IPC round-trip, logger level filtering, PacketStream overflow
- av: Standalone VideoEncoder (synthetic YUV -> libx264), VideoDecoder (test.mp4), AudioDecoder (test.mp4)
- http: Request/response serialisation round-trip, POST request, WebSocket text/binary frame encoding, client masking, control frames
- pacm: Package JSON round-trip, asset version selection, LocalPackage state management, manifest operations, error handling, InstallationState strings
- WebRTC module (unmaintainable due to Google API churn)
- Deprecated code:
av/deprecated/,UserManager,SharedObject - Dead connection classes from http/client.h
- CircleCI configuration
- Gitbook documentation tooling
- Vendored libuv, zlib, http-parser sources
- Legacy Poco and Anionu dependencies
- Last release of the 1.x series