Skip to content

librtmp2 0.12.0

Choose a tag to compare

@github-actions github-actions released this 10 Oct 17:05

Added

  • Native Windows support (x86_64 and ARM64, MSVC) for RTMP and RTMPS, client
    and server. All socket calls now go through src/net/, with a Unix backend
    (recv/send/sendmsg/poll, unchanged) and a Winsock backend
    (recv/send/WSASend/WSAPoll), selected at compile time. See
    docs/windows.md.
  • net::RawSocket / net::INVALID_SOCKET (the platform socket handle type and
    its "no socket" value) and Transport::from_tcp_stream().
  • Cross-platform loopback integration tests (tests/cross_platform_transport.rs)
    and native Windows x64/ARM64 CI jobs.

Changed

  • Socket-handle fields and methods (client_fd, server_fd,
    listener_fds(), Transport::fd(), Transport::new_plain(),
    TlsCtx::accept()) use net::RawSocket, which is i32 on Unix (no change)
    and u64 on Windows.
  • Server::listen_reuseport() / listen_tls_reuseport() return
    ErrorCode::Unsupported on Windows, which has no SO_REUSEPORT.
  • On Unix the transport now puts its socket into O_NONBLOCK mode when it
    takes it over (as the Windows backend does with FIONBIO). macOS ignores
    MSG_DONTWAIT on send/sendmsg, so a plaintext client could block once
    the socket buffer was full. On Windows a socket that cannot be made
    non-blocking is closed instead of stalling the poll loop.
  • examples/minimal_server binds 127.0.0.1:1935 by default (pass an
    address as the first argument to expose it), because it accepts every
    publish and play request.
  • CI builds, tests and cargo publish use the committed Cargo.lock
    (--locked).
  • A release tag is built and tested on macOS and Windows (x86_64 and ARM64)
    before anything is published; previously only Linux gated the release.
  • CI benchmark history is kept in bench/ on main (bench/latest.json,
    bench/releases/<tag>.json) instead of a separate bench-data branch;
    bench/ is excluded from the published crate.

Fixed

  • Async publish/play authorization: a decision that arrives after its stream
    was torn down or replaced (FCUnpublish/deleteStream, closeStream, a
    new createStream) is a silent no-op instead of authorizing whatever
    request came next. The withdrawn request keeps its slot until the stale
    completion or the timeout clears it, so has_pending_authorization() stays
    true until then.
  • A pending authorization reaped by the 15 s timeout now also closes the
    connection: the deny response is flushed, then the server tears the
    connection down in the same tick, so the client has to reconnect to try
    again. The reaped slot stays sealed, so a completion that arrives later can
    never authorize a newer request.
  • A republish on an already-publishing connection (for example a stream
    rename) no longer keeps relaying media under the old authorization while
    the new decision is pending, and a deferred-relay publisher's media counts
    toward the squat deadline.
  • poll(2) interrupted by a signal (EINTR) during a blocking send or a TLS
    accept is retried instead of failing the connection with Io.
  • The client's receive loop retries the read after a TLS WANT_WRITE once
    the socket is writable, instead of giving up on a writable socket.
  • Chunk reader: a fmt=3 chunk that starts a new message right after a fmt=0
    message repeats the fmt=0 timestamp as its delta (RTMP spec 5.3.1.2.4),
    instead of reusing the previous message's timestamp.
  • The client handles AbortMessage in all of its dispatch paths and discards
    the partial message on the aborted CSID.
  • Legacy FLV SoundFormat 14 is MP3 8 kHz, not Opus (Opus is only signaled
    through the E-RTMP ExHeader); reserved legacy sound format nibbles are
    rejected, and unregistered enhanced FourCCs are no longer labeled H.264.
  • AMF3_DATA messages have their one-byte AMF0 marker stripped even when it
    is the whole body, and re-parsing connect or the connect _result into
    a reused ConnectInfo/NegotiatedCaps no longer keeps stale optional
    fields.
  • The init cache ignores unpeeled ModEx wrappers instead of parsing them as
    an ex-header, and a route whose only cached video is the combined
    avc_header is classified as multitrack so congested players can resync
    on audio.
  • Client: a fatal recv error ends poll() with Io instead of returning
    Ok forever (which busy-spun embedders on a reset socket); a failed
    connect() resets the previous session so a later publish() cannot
    stream to the old server; a full send buffer while publishing is treated as
    "not writable yet" instead of aborting the session; and a receive that ends
    on a partial chunk no longer spins.
  • The transport's 10 s send poll timeout is an absolute deadline instead of
    restarting on every iteration.
  • examples/minimal_server registers its publish/play callbacks so it
    actually accepts streams, examples/minimal_client sends the frame type it
    declares, and bench_handshake/bench_relay reject --count 0 and stop
    on a dead viewer.
  • scripts/bench_report.py reads and writes its reports as UTF-8 and retries
    the baseline fetch, keeping the measurements when it fails.
  • Broken links in the API documentation (AuthDecision, split_host_port,
    Conn); CI now builds the docs with warnings as errors.

Benchmarks

Measured automatically for this release on a CI runner; the machine is described below. Raw data: bench-results-v0.12.0.json.

  • Measured: 2026-10-10 17:07:41 UTC · ba44578 · crate version 0.12.0 · workflow run
  • CPU: AMD EPYC 7763 64-Core Processor · 4 vCPUs
  • RAM: 15.6 GiB
  • System: Linux 6.17.0-1022-azure x86_64 · rustc 1.99.0 · GitHub-hosted ubuntu24 (image 20261004.327.1)
  • Noise: shared CI VM — CPU model, neighbouring load and the runner image change between runs, so treat absolute numbers as indicative.

No baseline yet (no release or previous main run has been recorded).

protocol

Benchmark Time Throughput
amf0_build_connect 219 ns —
chunk/write_read_roundtrip 5.89 µs ~663 MiB/s
flv/audio_tag_aac 1.25 ns —
flv/video_tag_h264 1.25 ns —
fourcc_to_video_codec_avc1 2.49 ns —
server_read_c1 1.07 µs —

relay

Benchmark Time Throughput
relay/publish_to_player/100 97.0 ms ~1031 elem/s
relay/publish_to_player/500 100.3 ms ~4984 elem/s

🟢 faster · 🔴 slower · ⚪ within the noise band (5–25 % depending on how comparable the two environments are, plus both runs' Criterion confidence intervals). Lower time is better.